Load libraries and public variables
# File that contains simulation output data in a HDF5 directory structure specified in "/publicVariables/createPublicVariables.Rmd"
simOutputH5 <- paste0("../../dataProcessing/simOutputH5Data/", experimentID, "_output.h5")
# A comprehensive table that contains all simulation input and calculated output metrics
allSimInputOutput <- read_feather("../allSimInputOutput.feather")
# This folder contains raw output files from the simulations. This is needed for calculate_para_sp_mcpsr()
rawSimOutFolder <- "/team/batch_SMOTNT/experiment1_output"
# Where figures are stored
figureBaseFolder <- "../figures/"
Validation: compare the protein synthesis rates with Weinberg 2016
weinbergData <- read_tsv("../externalData/weinberg_synthesis.txt")
Rows: 4839 Columns: 16
── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr (1): ORF
dbl (15): Length, RPF, mRNA, TE, IP, FEatg, FEcap, cRPF, cTE, uATG, utr, gc, pE, Ai, S
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
allSimInputOutput %>%
filter(paraCombo=="mRNAconstant") %>%
select(ORF, paraCombo, MPSR, dc, r) %>%
left_join(weinbergData[,c("ORF","S")], by = "ORF") %>%
mutate(S_perMin=S*60,
newcombo=factor(paraCombo,levels=dc.r.df$paraCombo[2:25])) %>%
ggplot(aes(x=MPSR, y=S_perMin)) +
geom_point() +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`,`~")), label.x.npc = 0.1, label.y.npc = 0.7, size=10) +
scale_x_log10() +
scale_y_log10() +
theme_bw() +
labs(x="Mean protein synthesis rates for mRNA constant",
y="Protein synthesis rate estimates by Weinberg et al 2016")
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 123 rows containing non-finite values (stat_smooth).
Warning: Removed 123 rows containing non-finite values (stat_cor).
Warning: Removed 123 rows containing missing values (geom_point).

# In exp11, the parameters had different names, dc=old_r, r=old_w.
# In exp11, the NMMC= RMMC in experiment1 (NMMC = normalized mean mRNA count, RMMC = relative mean mRNA count)
exp11_mRNAcount <- read_feather("../externalData/exp11_outcomeAll.feather") %>%
filter(para !="X1") %>%
select(NMMC, combo, ORF) %>%
`colnames<-`(c("NMMCexp11", "paraComboExp11", "ORF"))
# First join these data frames that have different colnames
tmpcombo <- tibble(paraComboExp11 = unique(exp11_mRNAcount$paraComboExp11),
old_r=sapply(strsplit(unique(exp11_mRNAcount$paraComboExp11), "_"), "[", 2),
old_w=sapply(strsplit(unique(exp11_mRNAcount$paraComboExp11), "_"), "[", 4),
paraCombo=paste0("dc_", 1-as.numeric(old_r), "_r_", old_w))
exp11_mRNAcount <- exp11_mRNAcount %>%
left_join(., tmpcombo, by="paraComboExp11")
figureS1 <- allSimInputOutput %>%
filter(paraCombo!="mRNAconstant") %>%
left_join(., exp11_mRNAcount, by = c("paraCombo"="paraCombo", "ORF"="ORF")) %>%
select(paraCombo, RMMC, NMMCexp11, dc, r) %>%
`colnames<-`(c("paraCombo", "AfterScaling", "BeforeScaling", "dc", "r")) %>%
pivot_longer(names_to = "key", values_to = "RMMCvalue", cols = 2:3) %>%
ggplot(aes(x=RMMCvalue, color=key)) +
geom_density() +
facet_grid(dc~r, labeller=labeller(dc=c("1"="100%", "0.8"="80%", "0.6"="60%", "0.4"="40%", "0.2"="20%", "0"="Co-trns 0%"), r=c("0"="Ribo prot indx = 0", "0.1"="0.1", "0.4"="0.4", "1"="1"), label_parsed)) +
labs(title = "Fig S1: mRNA counts when varying are laregely equal to when they are constant \nafter scaling the mRNA synthesis rates",
x="Relative mean mRNA count") +
scale_y_continuous() +
theme_bw() +
theme(text=element_text(size=13),
legend.title = element_blank(),
legend.position = "bottom")
figureS1

#ggsave(paste0(figureBaseFolder, "figures1/s_fig_1.png"), dpi=100, height = 6, width = 8)
###########################################################
allSimInputOutput %>%
filter(paraCombo!="mRNAconstant") %>%
select(paraCombo, RMMC, dc, r, geneLength_codon) %>%
mutate(sORl = ifelse(geneLength_codon >=512, "long", "short")) %>%
ggplot(aes(x=RMMC, color=sORl)) +
geom_density() +
facet_grid(dc~r, labeller=labeller(dc=c("1"="100%", "0.8"="80%", "0.6"="60%", "0.4"="40%", "0.2"="20%", "0"="Co-trns 0%"), r=c("0"="Ribo prot indx = 0", "0.1"="0.1", "0.4"="0.4", "1"="1"), label_parsed)) +
labs(x="Relative mean mRNA count") +
scale_y_continuous() +
theme_bw() +
theme(legend.title = element_blank(),
legend.position = "bottom",
strip.text.x = element_text(size=10),
strip.text.y = element_text(size=10))

###########################################################
allSimInputOutput %>%
filter(paraCombo!="mRNAconstant") %>%
select(paraCombo, RMMC, dc, r, mRNADecRateNeymotin_sec) %>%
mutate(fORs = ifelse(mRNADecRateNeymotin_sec >=0.0009431628, "fast", "slow")) %>%
ggplot(aes(x=RMMC, color=fORs)) +
geom_density() +
facet_grid(dc~r, labeller=labeller(dc=c("1"="100%", "0.8"="80%", "0.6"="60%", "0.4"="40%", "0.2"="20%", "0"="Co-trns 0%"), r=c("0"="Ribo prot indx = 0", "0.1"="0.1", "0.4"="0.4", "1"="1"), label_parsed)) +
labs(x="Relative mean mRNA count") +
scale_y_continuous() +
theme_bw() +
theme(legend.title = element_blank(),
legend.position = "bottom",
strip.text.x = element_text(size=10),
strip.text.y = element_text(size=10))

Fig S2.
allSimInputOutput %>%
filter(paraCombo=="dc_1_r_0", ORF!="YER053C-A", mRNADecRateNeymotin_sec!=0) %>%
ggplot(aes(x=MMC, y=MVMC, color = paraCombo)) +
geom_point(size = 0.5) +
geom_abline(linetype="dashed") +
theme_bw() +
theme(text = element_text(size = 13),
legend.position = "none",
strip.text = element_text(color="white"), # can't use element_blank() here because it gives error when p1+p2
plot.margin = margin(r = 0, unit = "pt"),
panel.grid = element_blank()
) +
labs(x = 'Mean of mRNA count',
y = 'Mean of variance in mRNA count') +
scale_color_manual(name="", labels=c("dc_1_r_0"="Co-trans 100% RiboProtect 0"), values = c("#1F78B4")) +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`,`~")), label.x.npc = 0.7, label.y.npc = 0.4, size=5) +
scale_x_log10() +
scale_y_log10()
`geom_smooth()` using formula 'y ~ x'

Fig. S3
allSimInputOutput %>%
filter(paraCombo!="mRNAconstant", ORF!="YER053C-A", mRNADecRateNeymotin_sec!=0) %>%
ggplot(aes(x=MMC, y=MVMC)) +
geom_point(size = 0.5) +
geom_abline(linetype="dashed") +
facet_grid(dc~r, labeller=labeller(dc=c("1"="100%", "0.8"="80%", "0.6"="60%", "0.4"="40%", "0.2"="20%", "0"="Co-trns 0%"), r=c("0"="Ribo prot indx = 0", "0.1"="0.1", "0.4"="0.4", "1"="1"), label_parsed)) +
theme_bw() +
theme(text = element_text(size = 13),
legend.position = "none",
plot.margin = margin(r = 0, unit = "pt"),
panel.grid = element_blank()
) +
labs(x = 'Mean of mRNA count',
y = 'Mean of variance in mRNA count') +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`,`~")), label.x.npc = 0.7, label.y.npc = 0.4, size=5) +
scale_x_log10() +
scale_y_log10()
`geom_smooth()` using formula 'y ~ x'

Fig S4: Sequence features correlate with the fano factor of protein synthesis rates for mRNA constant
plot_fun1 <- function(var1, var2){ allSimInputOutput%>% #var1:"MeanProteinSynRate".. var2:"mRNAconstant", "dc_1_r_0"
filter(paraCombo==var2, mRNADecRateNeymotin_sec!=0) %>%
select(ORF, MPSR, MVPS, iniProb_log10, mRNAabundance_log10, mRNADecRateNeymotin_sec_log10, CAI, geneLength_codon_log10) %>%
mutate(fano_protSyn = MVPS/MPSR) %>%
filter(fano_protSyn>0.3) %>% # filter out the two outliers
`colnames<-`(paste0("",c("ORF", "MeanProteinSynRate", "VarianceProteinSynRate", "iniProb_log10", "mRNALevel_log10", "DecRate_log10", "CAI", "geneLength_log10", "fano_protSynRate"))) %>%
pivot_longer(names_to = "feature", values_to = "featureVals", !c(ORF,MeanProteinSynRate, VarianceProteinSynRate, fano_protSynRate)) %>%
ggplot(aes_string(x="featureVals", y=var1)) +
geom_point(size=0.5) +
facet_wrap(~feature, scales="free", nrow=1, strip.position = "bottom") +
theme_bw() +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`,`~")), label.x.npc = 0.4, label.y.npc = 0.13, size=3) +
labs(x = "",
y = var1) +
scale_y_log10() +
theme(text = element_text(size = 13),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside" #to put the strip labels below x-axis
)
}
plot_fun1("fano_protSynRate", "mRNAconstant")
`geom_smooth()` using formula 'y ~ x'

Fig S5.
# MMDP = mRNAs marked for degradation proportion among mean total mRNA
allSimInputOutput %>%
filter(paraCombo == "dc_1_r_0", mRNADecRateNeymotin_sec!=0) %>%
ggplot(aes(x=MMDP, y=RMPSR)) +
geom_point(size=0.1) +
scale_x_log10() +
scale_y_log10() +
labs(x= "Proportion of mRNA marked for decay",
y = "Relative mean of protein synthesis rates",
title = "") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`,`~")), label.x.npc = 0.1, label.y.npc = 0.3, size=3) +
theme_bw() +
theme(text=element_text(size=13))
`geom_smooth()` using formula 'y ~ x'

Fig S6: relative CV = CV of the protein synthesis rate/CV of the mRNA count
allSimInputOutput %>%
filter(paraCombo=="dc_1_r_0", mRNADecRateNeymotin_sec != 0, ORF !="YCR024C-B") %>% #"YCR024C-B" is an outlier whose relCV = 23
mutate(relCV = CVPS/CVMC) %>%
select(ORF, relCV, iniProb_log10, mRNAabundance_log10, mRNADecRateNeymotin_sec_log10, CAI, geneLength_codon_log10) %>%
`colnames<-`(paste0("", c("ORF", "Relative_CV", "iniProb_log10", "mRNALevel_log10", "DecRate_log10", "CAI", "geneLength_log10"))) %>%
pivot_longer(names_to = "feature", values_to = "featureVals", -c(ORF, Relative_CV)) %>%
ggplot(aes(x=featureVals, y = Relative_CV)) +
geom_point(size=0.5) +
facet_wrap(~feature, scales="free", nrow=1, strip.position = "bottom") +
theme_bw() +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`,`~")), label.x.npc = 0.15, label.y.npc = 0.8, size=3) +
labs(x="",
y = "Relative CV") +
scale_y_log10() +
theme(text=element_text(size=13),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside") #to put the strip labels below x-axis
`geom_smooth()` using formula 'y ~ x'

Fig. S7:
allSimInputOutput %>%
filter(paraCombo == "dc_1_r_0", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", ORF!="YGR169C-A", ORF!="YLR106C", ORF!="YCR024C-B") %>%
select(MTT, MMDP, geneLength_codon, RMMDR) %>%
`colnames<-` (c("MeanTransTime", "mRNAMarkdDecProp", "geneLength_codon", "RelativeDecRate")) %>%
pivot_longer(names_to = "feature", values_to = "featureVals", !geneLength_codon) %>%
ggplot(aes(x=featureVals, y=geneLength_codon)) +
geom_point(size=0.1) +
facet_wrap(~feature, scales="free_x", nrow=1, strip.position = "bottom") +
scale_x_log10() +
scale_y_log10() +
labs(x= "",
y = "Gene length (codon)",
title = "dc_1_r_0") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`, `~")), label.x.npc = 0.3, label.y.npc = 0.1, size=3) +
theme_bw() +
theme(text=element_text(size=13),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside")
`geom_smooth()` using formula 'y ~ x'

allSimInputOutput %>%
filter(paraCombo == "dc_1_r_1", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A",ORF!="YGR169C-A", ORF!="YLR106C", ORF!="YCR024C-B") %>%
select(MTT, MMDP, geneLength_codon, RMMDR) %>%
`colnames<-` (c("MeanTransTime", "mRNAMarkdDecProp", "geneLength_codon", "RelativeDecRate")) %>%
pivot_longer(names_to = "feature", values_to = "featureVals", !geneLength_codon) %>%
ggplot(aes(x=featureVals, y=geneLength_codon)) +
geom_point(size=0.1) +
facet_wrap(~feature, scales="free_x", nrow=1, strip.position = "bottom") +
scale_x_log10() +
scale_y_log10() +
labs(x= "",
y = "Gene length (codon)",
title = "dc_1_r_1") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`,`~")), label.x.npc = 0.3, label.y.npc = 0.1, size=3) +
theme_bw() +
theme(text=element_text(size=13),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside")
`geom_smooth()` using formula 'y ~ x'

tmp <- allSimInputOutput %>%
filter(paraCombo == "dc_1_r_0", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A",ORF!="YGR169C-A", ORF!="YLR106C",ORF!="YCR024C-B") %>%
mutate(RDR=MMDR/mRNADecRateNeymotin_sec) %>%
select(RMTE, geneLength_codon, RDR)
summary(lm(RMTE~geneLength_codon+RDR, tmp))
Call:
lm(formula = RMTE ~ geneLength_codon + RDR, data = tmp)
Residuals:
Min 1Q Median 3Q Max
-0.082151 -0.007561 0.000916 0.008786 0.094288
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 6.209e-01 7.315e-03 84.88 <2e-16 ***
geneLength_codon -4.663e-05 8.409e-07 -55.45 <2e-16 ***
RDR 4.006e-01 7.144e-03 56.07 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.01489 on 4801 degrees of freedom
Multiple R-squared: 0.82, Adjusted R-squared: 0.8199
F-statistic: 1.093e+04 on 2 and 4801 DF, p-value: < 2.2e-16
# MMDP = mRNAs marked for degradation proportion among mean total mRNA
# MTT = mean translation time
allSimInputOutput %>%
filter(paraCombo == "dc_1_r_0", mRNADecRateNeymotin_sec!=0) %>%
ggplot(aes(x=MTT, y=MMDP)) +
geom_point(size=0.1) +
scale_x_log10() +
scale_y_log10() +
labs(x= "Mean translation time",
y = "Proportion of mRNA marked for decay",
title = "") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`, `~")), label.x.npc = 0.1, label.y.npc = 0.3, size=3) +
theme_bw()
`geom_smooth()` using formula 'y ~ x'

allSimInputOutput %>%
filter(paraCombo == "dc_0.2_r_0", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", ORF!="YGR169C-A", ORF!="YLR106C", ORF!="YCR024C-B") %>%
select(MTT, MMDP, geneLength_codon, RMMDR) %>%
`colnames<-` (c("MeanTransTime", "mRNAMarkdDecProp", "geneLength_codon", "RelativeDecRate")) %>%
pivot_longer(names_to = "feature", values_to = "featureVals", !geneLength_codon) %>%
ggplot(aes(x=featureVals, y=geneLength_codon)) +
geom_point(size=0.1) +
facet_wrap(~feature, scales="free_x", nrow=1, strip.position = "bottom") +
scale_x_log10() +
scale_y_log10() +
labs(x= "",
y = "Gene length (codon)",
title = "dc_0.2_r_0") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`,`~")), label.x.npc = 0.3, label.y.npc = 0.1, size=3) +
theme_bw() +
theme(text=element_text(size=13),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside")
`geom_smooth()` using formula 'y ~ x'

allSimInputOutput %>%
filter(paraCombo == "dc_0.2_r_1", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", ORF!="YGR169C-A", ORF!="YLR106C", ORF!="YCR024C-B") %>%
select(MTT, MMDP, geneLength_codon, RMMDR) %>%
`colnames<-` (c("MeanTransTime", "mRNAMarkdDecProp", "geneLength_codon", "RelativeDecRate")) %>%
pivot_longer(names_to = "feature", values_to = "featureVals", !geneLength_codon) %>%
ggplot(aes(x=featureVals, y=geneLength_codon)) +
geom_point(size=0.1) +
facet_wrap(~feature, scales="free_x", nrow=1, strip.position = "bottom") +
scale_x_log10() +
scale_y_log10() +
labs(x= "",
y = "Gene length (codon)",
title = "dc_0.2_r_1") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`, `~")), label.x.npc = 0.3, label.y.npc = 0.1, size=3) +
theme_bw() +
theme(text=element_text(size=13),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside")
Warning: Transformation introduced infinite values in continuous x-axis
Warning: Transformation introduced infinite values in continuous x-axis
Warning: Transformation introduced infinite values in continuous x-axis
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 1 rows containing non-finite values (stat_smooth).
Warning: Removed 1 rows containing non-finite values (stat_cor).

Fig. S8
allSimInputOutput %>%
filter(paraCombo == "dc_1_r_0", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", ORF!="YGR169C-A", ORF!="YLR106C", ORF!="YCR024C-B") %>%
select(RMTE, MTT, MMDP, geneLength_codon, RMMDR) %>%
`colnames<-` (c("RelMeanTE", "MeanTransTime", "mRNAMarkdDecProp", "geneLength_codon", "RelativeDecRate")) %>%
pivot_longer(names_to = "feature", values_to = "featureVals", !RelMeanTE) %>%
ggplot(aes(x=featureVals, y=RelMeanTE)) +
geom_point(size=0.1) +
facet_wrap(~feature, scales="free_x", nrow=1, strip.position = "bottom") +
scale_x_log10() +
scale_y_log10() +
labs(x= "",
y = "Relative mean TE",
title = "dc_1_r_0") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`, `~")), label.x.npc = 0.3, label.y.npc = 0.1, size=3) +
theme_bw() +
theme(text=element_text(size=13),
axis.text.x = element_text(size=rel(0.8)),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside")
`geom_smooth()` using formula 'y ~ x'

allSimInputOutput %>%
filter(paraCombo == "dc_0.8_r_0", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", ORF!="YGR169C-A", ORF!="YLR106C", ORF!="YCR024C-B") %>%
select(RMTE, MTT, MMDP, geneLength_codon, RMMDR) %>%
`colnames<-` (c("RelMeanTE", "MeanTransTime", "mRNAMarkdDecProp", "geneLength_codon", "RelativeDecRate")) %>%
pivot_longer(names_to = "feature", values_to = "featureVals", !RelMeanTE) %>%
ggplot(aes(x=featureVals, y=RelMeanTE)) +
geom_point(size=0.1) +
facet_wrap(~feature, scales="free_x", nrow=1, strip.position = "bottom") +
scale_x_log10() +
scale_y_log10() +
labs(x= "",
y = "Relative mean TE",
title = "dc_0.8_r_0") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`, `~")), label.x.npc = 0.3, label.y.npc = 0.1, size=3) +
theme_bw() +
theme(text=element_text(size=13),
axis.text.x = element_text(size=rel(0.8)),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside")
`geom_smooth()` using formula 'y ~ x'

allSimInputOutput %>%
filter(paraCombo == "dc_0.6_r_0", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", ORF!="YGR169C-A", ORF!="YLR106C", ORF!="YCR024C-B") %>%
select(RMTE, MTT, MMDP, geneLength_codon, RMMDR) %>%
`colnames<-` (c("RelMeanTE", "MeanTransTime", "mRNAMarkdDecProp", "geneLength_codon", "RelativeDecRate")) %>%
pivot_longer(names_to = "feature", values_to = "featureVals", !RelMeanTE) %>%
ggplot(aes(x=featureVals, y=RelMeanTE)) +
geom_point(size=0.1) +
facet_wrap(~feature, scales="free_x", nrow=1, strip.position = "bottom") +
scale_x_log10() +
scale_y_log10() +
labs(x= "",
y = "Relative mean TE",
title = "dc_0.6_r_0") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`, `~")), label.x.npc = 0.3, label.y.npc = 0.1, size=3) +
theme_bw() +
theme(text=element_text(size=13),
axis.text.x = element_text(size=rel(0.8)),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside")
`geom_smooth()` using formula 'y ~ x'

allSimInputOutput %>%
filter(paraCombo == "dc_0.4_r_0", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", ORF!="YGR169C-A", ORF!="YLR106C", ORF!="YCR024C-B") %>%
select(RMTE, MTT, MMDP, geneLength_codon, RMMDR) %>%
`colnames<-` (c("RelMeanTE", "MeanTransTime", "mRNAMarkdDecProp", "geneLength_codon", "RelativeDecRate")) %>%
pivot_longer(names_to = "feature", values_to = "featureVals", !RelMeanTE) %>%
ggplot(aes(x=featureVals, y=RelMeanTE)) +
geom_point(size=0.1) +
facet_wrap(~feature, scales="free_x", nrow=1,strip.position = "bottom") +
scale_x_log10() +
scale_y_log10() +
labs(x= "",
y = "Relative mean TE",
title = "dc_0.4_r_0") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`, `~")), label.x.npc = 0.3, label.y.npc = 0.1, size=3) +
theme_bw() +
theme(text=element_text(size=13),
axis.text.x = element_text(size=rel(0.8)),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside")
`geom_smooth()` using formula 'y ~ x'

allSimInputOutput %>%
filter(paraCombo == "dc_0.2_r_0", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", ORF!="YGR169C-A", ORF!="YLR106C", ORF!="YCR024C-B") %>%
select(RMTE, MTT, MMDP, geneLength_codon, RMMDR) %>%
`colnames<-` (c("RelMeanTE", "MeanTransTime", "mRNAMarkdDecProp", "geneLength_codon", "RelativeDecRate")) %>%
pivot_longer(names_to = "feature", values_to = "featureVals", !RelMeanTE) %>%
ggplot(aes(x=featureVals, y=RelMeanTE)) +
geom_point(size=0.1) +
facet_wrap(~feature, scales="free_x", nrow=1, strip.position = "bottom") +
scale_x_log10() +
scale_y_log10() +
labs(x= "",
y = "Relative mean TE",
title = "dc_0.2_r_0") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`, `~")), label.x.npc = 0.3, label.y.npc = 0.1, size=3) +
theme_bw() +
theme(text=element_text(size=13),
axis.text.x = element_text(size=rel(0.8)),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside")
`geom_smooth()` using formula 'y ~ x'

allSimInputOutput %>%
filter(paraCombo == "dc_0_r_0", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", ORF!="YGR169C-A", ORF!="YLR106C", ORF!="YCR024C-B") %>%
select(RMTE, MTT, MMDP, geneLength_codon, RMMDR) %>%
`colnames<-` (c("RelMeanTE", "MeanTransTime", "mRNAMarkdDecProp", "geneLength_codon", "RelativeDecRate")) %>%
pivot_longer(names_to = "feature", values_to = "featureVals", !RelMeanTE) %>%
ggplot(aes(x=featureVals, y=RelMeanTE)) +
geom_point(size=0.1) +
facet_wrap(~feature, scales="free_x", nrow=1, strip.position = "bottom") +
scale_x_log10() +
scale_y_log10() +
labs(x= "",
y = "Relative mean TE",
title = "dc_0_r_0") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`, `~")), label.x.npc = 0.3, label.y.npc = 0.1, size=3) +
theme_bw() +
theme(text=element_text(size=13),
axis.text.x = element_text(size=rel(0.8)),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside")
Warning: Transformation introduced infinite values in continuous x-axis
Warning: Transformation introduced infinite values in continuous x-axis
Warning: Transformation introduced infinite values in continuous x-axis
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 4804 rows containing non-finite values (stat_smooth).
Warning: Removed 4804 rows containing non-finite values (stat_cor).

allSimInputOutput %>%
filter(paraCombo == "dc_1_r_1", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", ORF!="YGR169C-A", ORF!="YLR106C", ORF!="YCR024C-B") %>%
select(RMTE, MTT, MMDP, geneLength_codon, RMMDR) %>%
`colnames<-` (c("RelMeanTE", "MeanTransTime", "mRNAMarkdDecProp", "geneLength_codon", "RelativeDecRate")) %>%
pivot_longer(names_to = "feature", values_to = "featureVals", !RelMeanTE) %>%
ggplot(aes(x=featureVals, y=RelMeanTE)) +
geom_point(size=0.1) +
facet_wrap(~feature, scales="free_x", nrow=1, strip.position = "bottom") +
scale_x_log10() +
scale_y_log10() +
labs(x= "",
y = "Relative mean TE",
title = "dc_1_r_1") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`, `~")), label.x.npc = 0.3, label.y.npc = 0.1, size=3) +
theme_bw() +
theme(text=element_text(size=13),
axis.text.x = element_text(size=rel(0.8)),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside")
`geom_smooth()` using formula 'y ~ x'

allSimInputOutput %>%
filter(paraCombo == "dc_0.2_r_1", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", ORF!="YGR169C-A", ORF!="YLR106C", ORF!="YCR024C-B") %>%
select(RMTE, MTT, MMDP, geneLength_codon, RMMDR) %>%
`colnames<-` (c("RelMeanTE", "MeanTransTime", "mRNAMarkdDecProp", "geneLength_codon", "RelativeDecRate")) %>%
pivot_longer(names_to = "feature", values_to = "featureVals", !RelMeanTE) %>%
ggplot(aes(x=featureVals, y=RelMeanTE)) +
geom_point(size=0.1) +
facet_wrap(~feature, scales="free_x", nrow=1, strip.position = "bottom") +
scale_x_log10() +
scale_y_log10() +
labs(x= "",
y = "Relative mean TE",
title = "dc_0.2_r_1") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`, `~")), label.x.npc = 0.3, label.y.npc = 0.1, size=3) +
theme_bw() +
theme(text=element_text(size=13),
axis.text.x = element_text(size=rel(0.8)),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside")
Warning: Transformation introduced infinite values in continuous x-axis
Warning: Transformation introduced infinite values in continuous x-axis
Warning: Transformation introduced infinite values in continuous x-axis
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 1 rows containing non-finite values (stat_smooth).
Warning: Removed 1 rows containing non-finite values (stat_cor).

allSimInputOutput %>%
filter(paraCombo == "dc_1_r_0", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", ORF!="YGR169C-A", ORF!="YLR106C", ORF!="YCR024C-B") %>%
select(MMDP, RMMDR) %>%
ggplot(aes(x=MMDP, y=RMMDR)) +
geom_point(size=0.1) +
labs(x= "MMDP",
y = "Relative decay rates",
title = "dc_1_r_0") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`, `~")), label.x.npc = 0.3, label.y.npc = 0.1, size=3) +
theme_bw() +
theme(text=element_text(size=13),
axis.text.x = element_text(size=rel(0.8)),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside")
`geom_smooth()` using formula 'y ~ x'

allSimInputOutput %>%
filter(paraCombo == "dc_0.2_r_0", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", ORF!="YGR169C-A", ORF!="YLR106C", ORF!="YCR024C-B") %>%
select(MMDP, RMMDR) %>%
ggplot(aes(x=MMDP, y=RMMDR)) +
geom_point(size=0.1) +
scale_x_log10() +
scale_y_log10() +
labs(x= "MMDP",
y = "Relative decay rates",
title = "dc_0.2_r_0") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`, `~")), label.x.npc = 0.3, label.y.npc = 0.1, size=3) +
theme_bw() +
theme(text=element_text(size=13),
axis.text.x = element_text(size=rel(0.8)),
strip.text = element_text(color="black"), # can't use element_blank() here because it gives error when p1+p2
strip.background = element_blank(),
strip.placement = "outside")
`geom_smooth()` using formula 'y ~ x'

Fig. S9
lifetimeDistri<- function(genevec){
dfplot <- cbind(dc.r.df[c(2:5, 22:25), ], data.frame(matrix(NA, ncol= 5000, nrow=8*3))) %>%
mutate(ORF=c(rep(genevec[1], 8), rep(genevec[2], 8), rep(genevec[3], 8))) %>%
relocate(ORF)
for(i in 1:8){dfplot[i, 6:5005] = as.vector(h5read(simOutputH5, paste0(genevec[1], "/mRNA_lifeTimes/", dfplot$paraCombo[i])))}
for(i in 9:16){dfplot[i, 6:5005] = as.vector(h5read(simOutputH5, paste0(genevec[2], "/mRNA_lifeTimes/", dfplot$paraCombo[i])))}
for(i in 17:24){dfplot[i, 6:5005] = as.vector(h5read(simOutputH5, paste0(genevec[3], "/mRNA_lifeTimes/", dfplot$paraCombo[i])))}
dfplot %>%
pivot_longer(names_to = "varyingParaCombo", values_to = "lifeTimes", cols = 6:5005) %>%
ggplot(aes(lifeTimes, fill=dc)) +
geom_density(alpha=0.5, color=NA) +
facet_grid(factor(ORF, levels=genevec)~r,
labeller = labeller(r=c("0"="Ribo prot index 0", "0.1"="0.1", "0.4"="0.4", "1"="1"))) +
scale_x_log10(labels = scales::comma_format(accuracy=1L)) +
scale_fill_discrete(name="CMD level",
labels = c("0"="0", "0.2"="20%", "0.6"="60%", "1"="100%")) +
theme_bw() +
labs(x=paste0("mRNA life time distribution (log10)")) +
theme(
legend.position = "top",
legend.justification = "left",
text = element_text(size = 13),
axis.text.x = element_text(size=8)) +
geom_vline(data=filter(dfplot, ORF==genevec[1]), aes(xintercept = 1/simInputFeatures$mRNADecRateNeymotin_sec[which(simInputFeatures$ORF==genevec[1])]), linetype="dashed", color="dark grey") + #1049.856 =1/simInputFeatures$mRNADecRateNeymotin_sec[1] # 1049.856 is the input lifetime for YAL001C
geom_vline(data=filter(dfplot, ORF==genevec[2]), aes(xintercept = 1/simInputFeatures$mRNADecRateNeymotin_sec[which(simInputFeatures$ORF==genevec[2])]), linetype="dashed", color="dark grey") +
geom_vline(data=filter(dfplot, ORF==genevec[3]), aes(xintercept = 1/simInputFeatures$mRNADecRateNeymotin_sec[which(simInputFeatures$ORF==genevec[3])]), linetype="dashed", color="dark grey")
# the above lines are the average life time calculated from input decay rates
}
lifetimeDistri(c("YAL001C", "YKR075C", "YBR011C"))

lifetimeDistri(c("YLR106C", "YKR054C", "YHR099W")) # longest genes
Warning: Removed 6188 rows containing non-finite values (stat_density).

lifetimeDistri(c("YAR002C-A", "YBL050W", "YBR003W"))

tmpdf <- data.frame(lifetime=log10(as.numeric(dfplot[1, 6:5005])))
Error in data.frame(lifetime = log10(as.numeric(dfplot[1, 6:5005]))) :
object 'dfplot' not found
Fig. S
NOTES: Output decay rate = 1/mean lifetime https://en.wikipedia.org/wiki/Particle_decay
Total output decay rate = output decay rate * output mean mRNA count
Total input decay rate = input decay rate * mRNAabundance
Total synthesis rate = a scaled constant
(The above rates are all gene-specific)
Summary: changing total output decay rate is a result of changing co-translational decay and ribosome protection. In order to maintain the constant mRNA level, we have to scale the total synthesis rates to counter-effect the changing output decay rates.
When co-translational decay is higher than 0, there’s always a surplus of mRNAs marked for decay, that are not accounted when calculating total decay probabilities (They’re not accounted because they already have decay machinery bound to them, so cannot be accounted again into the mRNA pool that can still be degraded). Therefore the synthesis rates are scaled, in order to maintain a stable relative mRNA count (= mean output mRNA count/mRNAabundance) for it to be close to 1 (Supp Fig 1). The mean output mRNA count for each gene is a result of the balance between its scaled synthesis rate and total output decay rate. In other words, the total output decay rate directly respond to the scaled synthesis rate, rather than the input decay rate.
The scaled total synthesis rates are the smallest when co-translational decay = 100%, so that the total real-time mRNA count can be close to mRNAabundance even with the highest amount of mRNAs marked for decay. In contrast, the scaled total synthesis rates are the largest and equal to the total input decay rates when co-trans decay = 0% (Supp Fig 2a), because there is 0 mRNA marked for decay.
Hypothetically, the total output decay rates should equal to the total synthesis rates in order to maintain the real-time mRNA count to be largely the same at the beginning and the end of the simulation. If unequal, the real-time mRNA count should either go up or down as the simulation continues compared to the begining amount (i.e. mRNAabundance). However, our results show that the total output decay rates are slightly larger than the scaled synthesis rates across all the parameter combos (Supp Fig 2b. this is the part I don’t understand, is it coz the total output decay rates include considering mRNAsMarkedForDecay, but the total scaled synthesis rates doesn’t include mRNAsMarkedForDecay), and that’s somehow contributing to the mean real-time mRNA count being equal to mRNAabundance as shown in Supp Fig 1.
Because the output decay rates directly respond to total synthesis rates, they are influenced by the para combos in the same way that total synthesis rates are. That explains why Supp Fig 2c is similar to Supp Fig 2a in that the peaks skew to the right as co-translational decay ratio goes down. However in Supp Fig 2a, the ratio (scaled synthesis rates V.S. total input decay rates) skewed from less than 1 to 1; while in Supp Fig 2c, the ratio (total output decay rates V.S. total input decay rates) skewed from 1 to larger than 1. This would make sense if we can explain what’s going on in Supp Fig 2b.
Meanwhile, the output decay rates for short genes are much less affected by different co-translational decay proportions than long genes (Supp Fig 2d). This should be a reflection that the total synthesis rates for short genes are changing less with changing co-translational decay.
Supp Fig 2a: The scaled synthesis rates are the smallest when co-trans decay = 100%, while theythe largest and equal to the total input decay rates when co-trans decay = 0%
Supp Fig 2b: Total output mRNA decay rates are slightly larger than scaled mRNA synthesis rates , but the ratio stays stable with changing parameters (I don’t understand why the decay rates have to be larger)
Supp Fig 2c: Output decay rates respond to scaled synthesis rates, therefore its ratio against input decay rates shows similar patter as scaled synthesis rates in Fig 2
Supp Fig 2d: Output decay rates for short genes are much less affected by different -translational decay than long genes
outcomeAll_exp11 <- read_feather(paste0(basefolder, expID, "/externalData/exp11_outcomeAll.feather"))
Error in paste0(basefolder, expID, "/externalData/exp11_outcomeAll.feather") :
object 'basefolder' not found
Fig. S
l %>%
filter(paraCombo=="dc_1_r_0", mRNADecRateNeymotin_sec!=0, ORF!="YCR024C-B", mRNAabundance!=1) %>%
mutate(relativeFano = RMVPS/RMPSR) %>%
ggplot(aes(x=RMPSR, y=relativeFano)) +
geom_point(size=0.1) +
scale_x_log10() +
scale_y_log10() +
labs(x= "Realtive mean protein synthesis rate",
y = "Relative fano factor in protein synthesis rate",
title = "") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`, `~")), label.x.npc = 0.1, label.y.npc = 0.3, size=3) +
theme_bw()
Error in filter(., paraCombo == "dc_1_r_0", mRNADecRateNeymotin_sec != :
object 'l' not found
outcomeAll %>%
filter(combo == "dc_1_r_0", GreshamDecRate!=0,ORF!="YCR024C-B",rand_mRNA!=1) %>%
ggplot(aes(x=MMDR,y=RMVTE)) +
geom_point(size=0.1) +
scale_x_log10() +
scale_y_log10() +
labs(x= "Mean ribosome density",
y = "Relative mean of variance in translation efficiency",
title = "") +
geom_smooth(method="lm") +
stat_cor(aes(label=paste(..r.label.., sep = "~`,`~")), label.x.npc = 0.1, label.y.npc = 0.3, size=3) +
theme_bw()
`geom_smooth()` using formula 'y ~ x'

Figure S.
# calculating the mean number of free ribos (averaged over simuTime and techReps) for all dc.r.paraCombos
# RMFR = relative mean free ribo
mfr <- c()
for(i in 1:nrow(dc.r.df)) # loop through the dc/r parameter space to calculate the mean free ribo
{
# free_ribo averaged by simuTime and techReps
mfr <- c(mfr, mean(h5read(simOutputH5, paste("free_ribo_tRNA_perMin", dc.r.df$paraCombo[i], "ribo", sep="/")), na.rm = TRUE))
# set na.rm=T because in rep 66 again there's an NA at the last minute, which won't affect the overall mean
}
rmfr <- mfr/mfr[1]
rmfr_df <- data.frame(RMFR = rmfr,
MFR = mfr,
para = dc.r.df$para)
Warning: Unknown or uninitialised column: `para`.
Error in data.frame(RMFR = rmfr, MFR = mfr, para = dc.r.df$para) :
arguments imply differing number of rows: 25, 0
make_heatmap <- function(orderVar, outputVar, legendName, titleY)
{
colorvec <- quantile(allSimInputOutput[[outputVar]])
tmp <- (allSimInputOutput%>%filter(paraCombo=="dc_1_r_0"))[, c("ORF", orderVar)]
tmp <- tmp[order(tmp[, 2], decreasing = T), ]
tmp$newid_dc1r0 <- 1:4839
allSimInputOutput %>%
filter(paraCombo!="mRNAconstant") %>%
left_join(., tmp[, c("ORF", "newid_dc1r0")], by = "ORF") %>%
mutate(dc_fct=factor(dc, levels=c("1", "0.8", "0.6", "0.4", "0.2", "0"))) %>%
ggplot(aes_string(x = "r",
y = "factor(newid_dc1r0)",
fill = outputVar)) +
geom_raster() +
theme_bw() +
scale_fill_gradientn(colours = c("#377eb8", "white", "#e41a1c"), # blue white red
values = scales::rescale(colorvec), name=legendName) +
facet_wrap(~dc_fct, nrow=1, labeller=labeller(dc_fct=c("1"="Co-trans 100%", "0.8"="80%", "0.6"="60%", "0.4"="40%", "0.2"="20%", "0"="0"))) +
labs ( x = "Ribosome protection index r",
y = titleY,
title = "") +
theme(text = element_text(size = 18),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
panel.border = element_blank(), # remove the grid lines in facet_grid
panel.spacing=unit(0, "lines")) + # reset the spacing between facets
guides(fill = guide_colourbar(barwidth = 1, barheight = 10)) +
scale_x_discrete(expand = c(0, 0)) # remove the extra space beyond xlim
}
# 1st var= the variable column the sorting is based on
# 2nd var= the variable column presented in the heatmap
# 3rd var= the legend text
# 4th var= y-axis title
make_heatmap("RMTE", "RMTE", "Relative\nmean translation\nefficiency", "Genes ranked by the first column")
Warning in xtfrm.data.frame(x) : cannot xtfrm data frames

make_heatmap("RMVTE", "RMVTE", "Relative mean\nof the variance\nin translation\nefficiency", "Genes ranked by the first column")
Warning in xtfrm.data.frame(x) : cannot xtfrm data frames

########################################################## add a plot for mRNAs marked for decay
colorvec <- quantile((allSimInputOutput%>% filter(paraCombo!="mRNAconstant", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A"))$MMDP)
tmp <- (allSimInputOutput%>%filter(paraCombo=="dc_1_r_0"))[, c("ORF", "RMTE")]
tmp <- tmp[order(tmp[, 2], decreasing = T), ]
Warning in xtfrm.data.frame(x) : cannot xtfrm data frames
tmp$newid_dc1r0 <- 1:4839
allSimInputOutput %>%
mutate(dc_fct=factor(dc, levels=c("1", "0.8", "0.6", "0.4", "0.2", "0"))) %>%
filter(paraCombo!="mRNAconstant", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", dc!=0) %>%
left_join(., tmp[, c("ORF", "newid_dc1r0")], by = "ORF") %>%
ggplot(aes(x = r,
y = factor(newid_dc1r0),
#y = as.character(newid_geneLength_codon), # genes are sorted by geneLength_codon within each group
fill = MMDP)) +
geom_raster() +
theme_bw() +
scale_fill_gradientn(colours = c("#377eb8", "white", "#e41a1c"), # blue white red
values = scales::rescale(colorvec), name="mRNAs marked\nfor decay ratio") +
facet_wrap(~dc_fct, nrow=1, labeller=labeller(dc_fct=c("1"="Co-trans 100%", "0.8"="80%", "0.6"="60%", "0.4"="40%", "0.2"="20%", "0"="0%"))) +
labs ( x = "Ribosome protection index w",
y = "Genes ranked by the first column in translation efficiency plot",
title = "") +
theme(text = element_text(size = 18),
plot.title = element_text(size=rel(1.5)),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
panel.border = element_blank(), # remove the grid lines in facet_grid
panel.spacing=unit(0, "lines")) + # reset the spacing between facets
guides(fill = guide_colourbar(barwidth = 1, barheight = 10)) +
scale_x_discrete(expand = c(0, 0)) # remove the extra space beyond xlim

########################################################## add another plot for mRNAs marked for decay
colorvec <- quantile((allSimInputOutput%>% filter(paraCombo!="mRNAconstant", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A"))$MMDP)
tmp <- (allSimInputOutput%>%filter(paraCombo=="dc_1_r_0"))[, c("ORF", "RMVTE")]
tmp <- tmp[order(tmp[, 2], decreasing = T), ]
Warning in xtfrm.data.frame(x) : cannot xtfrm data frames
tmp$newid_dc1r0 <- 1:4839
allSimInputOutput %>%
mutate(dc_fct=factor(dc, levels=c("1", "0.8", "0.6", "0.4", "0.2", "0"))) %>%
filter(paraCombo!="mRNAconstant", mRNADecRateNeymotin_sec!=0, ORF!="YER053C-A", dc!=0) %>%
left_join(., tmp[, c("ORF", "newid_dc1r0")], by = "ORF") %>%
ggplot(aes(x = r,
y = factor(newid_dc1r0),
fill = MMDP)) +
geom_raster() +
theme_bw() +
scale_fill_gradientn(colours = c("#377eb8", "white", "#e41a1c"), # blue white red
values = scales::rescale(colorvec), name="mRNAs marked\nfor decay ratio") +
facet_wrap(~dc_fct, nrow=1, labeller=labeller(dc_fct=c("1"="Co-trans 100%", "0.8"="80%", "0.6"="60%", "0.4"="40%", "0.2"="20%", "0"="0%"))) +
labs ( x = "Ribosome protection index w",
y = "Genes ranked by the first column in translation efficiency plot",
title = "") +
theme(text = element_text(size = 18),
plot.title = element_text(size=rel(1.5)),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
panel.border = element_blank(), # remove the grid lines in facet_grid
panel.spacing=unit(0, "lines")) + # reset the spacing between facets
guides(fill = guide_colourbar(barwidth = 1, barheight = 10)) +
scale_x_discrete(expand = c(0, 0)) # remove the extra space beyond xlim

# 1st var= the variable column the sorting is based on
# 2nd var= the variable column presented in the heatmap
# 3rd var= the legend text
# 4th var= y-axis title
make_heatmap("RMPSR", "RMPSR", "Relative\nmean protein\nsyn rate", "Genes ranked by the first column")
Warning in xtfrm.data.frame(x) : cannot xtfrm data frames

make_heatmap("RMVPS", "RMVPS", "Relative\nmean of variance in\nprotein syn rate", "Genes ranked by the first column")
Warning in xtfrm.data.frame(x) : cannot xtfrm data frames

make_heatmap_tmp <- function(orderVar, outputVar, legendName, titleY)
{
colorvec <- quantile(allSimInputOutput[[outputVar]])
tmp <- (allSimInputOutput%>%filter(paraCombo=="dc_1_r_0"))[, c("ORF", orderVar)]
tmp <- tmp[order(tmp[, 2], decreasing = T), ]
tmp$newid_dc1r0 <- 1:4839
allSimInputOutput %>%
filter(paraCombo!="mRNAconstant", RMVTBR!=Inf) %>%
left_join(.,tmp[, c("ORF", "newid_dc1r0")], by = "ORF") %>%
mutate(dc_fct=factor(dc, levels=c("1", "0.8", "0.6", "0.4", "0.2", "0"))) %>%
ggplot(aes_string(x = "r",
y = "factor(newid_dc1r0)",
fill = outputVar)) +
geom_raster() +
theme_bw() +
scale_fill_gradientn(colours = c("#377eb8", "white", "#e41a1c"), # blue white red
values = scales::rescale(colorvec), name=legendName) +
facet_wrap(~dc_fct, nrow=1, labeller=labeller(dc_fct=c("1"="Co-trans 100%", "0.8"="80%", "0.6"="60%", "0.4"="40%", "0.2"="20%", "0"="0"))) +
labs ( x = "Ribosome protection index r",
y = titleY,
title = "") +
theme(text = element_text(size = 18),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
panel.border = element_blank(), # remove the grid lines in facet_grid
panel.spacing=unit(0, "lines")) + # reset the spacing between facets
guides(fill = guide_colourbar(barwidth = 1, barheight = 10)) +
scale_x_discrete(expand = c(0, 0)) # remove the extra space beyond xlim
}
make_heatmap_tmp("RMTE", "RMVTBR", "Relative\nvariance in total\nbound ribosomes", "Genes ranked by the first column in relative TE")
Error in quantile.default(allSimInputOutput[[outputVar]]) :
missing values and NaN's not allowed if 'na.rm' is FALSE
LS0tCnRpdGxlOiAiRmlndXJlcyBmb3IgbWFudXNjcmlwdCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKTG9hZCBsaWJyYXJpZXMgYW5kIHB1YmxpYyB2YXJpYWJsZXMKYGBge3IsIGluY2x1ZGU9RkFMU0V9IAojIFRoaXMgY2h1bmsgd2lsbCBiZSBldmFsdWF0ZWQgYnV0IHRoZSBvdXRwdXQgaXMgc3VwcHJlc3NlZApybWFya2Rvd246OnJlbmRlcigiLi4vLi4vcHVibGljVmFyaWFibGVzL2NyZWF0ZVB1YmxpY1ZhcmlhYmxlcy5SbWQiKQpgYGAKCmBgYHtyfQojIEZpbGUgdGhhdCBjb250YWlucyBzaW11bGF0aW9uIG91dHB1dCBkYXRhIGluIGEgSERGNSBkaXJlY3Rvcnkgc3RydWN0dXJlIHNwZWNpZmllZCBpbiAiL3B1YmxpY1ZhcmlhYmxlcy9jcmVhdGVQdWJsaWNWYXJpYWJsZXMuUm1kIgpzaW1PdXRwdXRINSA8LSBwYXN0ZTAoIi4uLy4uL2RhdGFQcm9jZXNzaW5nL3NpbU91dHB1dEg1RGF0YS8iLCBleHBlcmltZW50SUQsICJfb3V0cHV0Lmg1IikKCiMgQSBjb21wcmVoZW5zaXZlIHRhYmxlIHRoYXQgY29udGFpbnMgYWxsIHNpbXVsYXRpb24gaW5wdXQgYW5kIGNhbGN1bGF0ZWQgb3V0cHV0IG1ldHJpY3MKYWxsU2ltSW5wdXRPdXRwdXQgPC0gcmVhZF9mZWF0aGVyKCIuLi9hbGxTaW1JbnB1dE91dHB1dC5mZWF0aGVyIikKCiMgVGhpcyBmb2xkZXIgY29udGFpbnMgcmF3IG91dHB1dCBmaWxlcyBmcm9tIHRoZSBzaW11bGF0aW9ucy4gVGhpcyBpcyBuZWVkZWQgZm9yIGNhbGN1bGF0ZV9wYXJhX3NwX21jcHNyKCkKcmF3U2ltT3V0Rm9sZGVyIDwtICIvdGVhbS9iYXRjaF9TTU9UTlQvZXhwZXJpbWVudDFfb3V0cHV0IgoKIyBXaGVyZSBmaWd1cmVzIGFyZSBzdG9yZWQKZmlndXJlQmFzZUZvbGRlciA8LSAiLi4vZmlndXJlcy8iCmBgYAoKVmFsaWRhdGlvbjogY29tcGFyZSB0aGUgcHJvdGVpbiBzeW50aGVzaXMgcmF0ZXMgd2l0aCBXZWluYmVyZyAyMDE2CmBgYHtyfQp3ZWluYmVyZ0RhdGEgPC0gcmVhZF90c3YoIi4uL2V4dGVybmFsRGF0YS93ZWluYmVyZ19zeW50aGVzaXMudHh0IikKCmFsbFNpbUlucHV0T3V0cHV0ICU+JSAKICBmaWx0ZXIocGFyYUNvbWJvPT0ibVJOQWNvbnN0YW50IikgJT4lIAogIHNlbGVjdChPUkYsIHBhcmFDb21ibywgTVBTUiwgZGMsIHIpICU+JQogIGxlZnRfam9pbih3ZWluYmVyZ0RhdGFbLCBjKCJPUkYiLCAiUyIpXSwgYnkgPSAiT1JGIikgJT4lCiAgbXV0YXRlKFNfcGVyTWluPVMqNjAsCiAgICAgICAgIG5ld2NvbWJvPWZhY3RvcihwYXJhQ29tYm8sIGxldmVscz1kYy5yLmRmJHBhcmFDb21ib1syOjI1XSkpICU+JQogIGdncGxvdChhZXMoeD1NUFNSLCB5PVNfcGVyTWluKSkgKwogICAgZ2VvbV9wb2ludCgpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArCiAgICBzdGF0X2NvcihhZXMobGFiZWw9cGFzdGUoLi5yLmxhYmVsLi4sICBzZXAgPSAifmAsIGB+IikpLCBsYWJlbC54Lm5wYyA9IDAuMSwgbGFiZWwueS5ucGMgPSAwLjcsIHNpemU9MTApICsKICAgIHNjYWxlX3hfbG9nMTAoKSArCiAgICBzY2FsZV95X2xvZzEwKCkgKwogICAgdGhlbWVfYncoKSArCiAgICBsYWJzKHg9Ik1lYW4gcHJvdGVpbiBzeW50aGVzaXMgcmF0ZXMgZm9yIG1STkEgY29uc3RhbnQiLAogICAgICAgICB5PSJQcm90ZWluIHN5bnRoZXNpcyByYXRlIGVzdGltYXRlcyBieSBXZWluYmVyZyBldCBhbCAyMDE2IikKYGBgCgoKYGBge3IgZmlnLndpZHRoPTEwfQojIEluIGV4cDExLCB0aGUgcGFyYW1ldGVycyBoYWQgZGlmZmVyZW50IG5hbWVzLCBkYz1vbGRfciwgcj1vbGRfdy4KIyBJbiBleHAxMSwgdGhlIE5NTUM9IFJNTUMgaW4gZXhwZXJpbWVudDEgKE5NTUMgPSBub3JtYWxpemVkIG1lYW4gbVJOQSBjb3VudCwgUk1NQyA9IHJlbGF0aXZlIG1lYW4gbVJOQSBjb3VudCkKZXhwMTFfbVJOQWNvdW50IDwtIHJlYWRfZmVhdGhlcigiLi4vZXh0ZXJuYWxEYXRhL2V4cDExX291dGNvbWVBbGwuZmVhdGhlciIpICU+JQogICAgICAgICAgICAgICAgICAgZmlsdGVyKHBhcmEgIT0iWDEiKSAlPiUKICAgICAgICAgICAgICAgICAgIHNlbGVjdChOTU1DLCBjb21ibywgT1JGKSAlPiUKICAgICAgICAgICAgICAgICAgIGBjb2xuYW1lczwtYChjKCJOTU1DZXhwMTEiLCAicGFyYUNvbWJvRXhwMTEiLCAiT1JGIikpCiMgRmlyc3Qgam9pbiB0aGVzZSBkYXRhIGZyYW1lcyB0aGF0IGhhdmUgZGlmZmVyZW50IGNvbG5hbWVzCnRtcGNvbWJvIDwtIHRpYmJsZShwYXJhQ29tYm9FeHAxMSA9IHVuaXF1ZShleHAxMV9tUk5BY291bnQkcGFyYUNvbWJvRXhwMTEpLAogICAgICAgICAgICAgICAgICAgb2xkX3I9c2FwcGx5KHN0cnNwbGl0KHVuaXF1ZShleHAxMV9tUk5BY291bnQkcGFyYUNvbWJvRXhwMTEpLCAiXyIpLCAiWyIsIDIpLCAKICAgICAgICAgICAgICAgICAgIG9sZF93PXNhcHBseShzdHJzcGxpdCh1bmlxdWUoZXhwMTFfbVJOQWNvdW50JHBhcmFDb21ib0V4cDExKSwgIl8iKSwgIlsiLCA0KSwgCiAgICAgICAgICAgICAgICAgICBwYXJhQ29tYm89cGFzdGUwKCJkY18iLCAxLWFzLm51bWVyaWMob2xkX3IpLCAiX3JfIiwgb2xkX3cpKQpleHAxMV9tUk5BY291bnQgPC0gZXhwMTFfbVJOQWNvdW50ICU+JQogICAgICAgICAgICAgICAgICAgbGVmdF9qb2luKC4sIHRtcGNvbWJvLCBieT0icGFyYUNvbWJvRXhwMTEiKQoKZmlndXJlUzEgPC0gYWxsU2ltSW5wdXRPdXRwdXQgJT4lCiAgICBmaWx0ZXIocGFyYUNvbWJvIT0ibVJOQWNvbnN0YW50IikgJT4lCiAgICBsZWZ0X2pvaW4oLiwgZXhwMTFfbVJOQWNvdW50LCBieSA9IGMoInBhcmFDb21ibyI9InBhcmFDb21ibyIsICJPUkYiPSJPUkYiKSkgJT4lCiAgICBzZWxlY3QocGFyYUNvbWJvLCBSTU1DLCBOTU1DZXhwMTEsIGRjLCByKSAlPiUKICAgIGBjb2xuYW1lczwtYChjKCJwYXJhQ29tYm8iLCAiQWZ0ZXJTY2FsaW5nIiwgIkJlZm9yZVNjYWxpbmciLCAiZGMiLCAiciIpKSAlPiUKICAgIHBpdm90X2xvbmdlcihuYW1lc190byA9ICJrZXkiLCB2YWx1ZXNfdG8gPSAiUk1NQ3ZhbHVlIiwgY29scyA9IDI6MykgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9Uk1NQ3ZhbHVlLCBjb2xvcj1rZXkpKSArCiAgICAgICAgZ2VvbV9kZW5zaXR5KCkgKwogICAgICAgIGZhY2V0X2dyaWQoZGN+ciwgbGFiZWxsZXI9bGFiZWxsZXIoZGM9YygiMSI9IjEwMCUiLCAiMC44Ij0iODAlIiwgIjAuNiI9IjYwJSIsICIwLjQiPSI0MCUiLCAiMC4yIj0iMjAlIiwgIjAiPSJDby10cm5zIDAlIiksIHI9YygiMCI9IlJpYm8gcHJvdCBpbmR4ID0gMCIsICIwLjEiPSIwLjEiLCAiMC40Ij0iMC40IiwgIjEiPSIxIiksIGxhYmVsX3BhcnNlZCkpICsgCiAgICAgICAgbGFicyh0aXRsZSA9ICJGaWcgUzE6IG1STkEgY291bnRzIHdoZW4gdmFyeWluZyBhcmUgbGFyZWdlbHkgZXF1YWwgdG8gd2hlbiB0aGV5IGFyZSBjb25zdGFudCBcbmFmdGVyIHNjYWxpbmcgdGhlIG1STkEgc3ludGhlc2lzIHJhdGVzIiwgCiAgICAgICAgICAgICB4PSJSZWxhdGl2ZSBtZWFuIG1STkEgY291bnQiKSArCiAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKCkgKwogICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTMpLCAKICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKZmlndXJlUzEKCiNnZ3NhdmUocGFzdGUwKGZpZ3VyZUJhc2VGb2xkZXIsICJmaWd1cmVzMS9zX2ZpZ18xLnBuZyIpLCBkcGk9MTAwLCBoZWlnaHQgPSA2LCB3aWR0aCA9IDgpCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmFsbFNpbUlucHV0T3V0cHV0ICU+JQogICAgZmlsdGVyKHBhcmFDb21ibyE9Im1STkFjb25zdGFudCIpICU+JQogICAgc2VsZWN0KHBhcmFDb21ibywgUk1NQywgZGMsIHIsIGdlbmVMZW5ndGhfY29kb24pICU+JQogICAgbXV0YXRlKHNPUmwgPSBpZmVsc2UoZ2VuZUxlbmd0aF9jb2RvbiA+PTUxMiwgImxvbmciLCAic2hvcnQiKSkgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9Uk1NQywgY29sb3I9c09SbCkpICsKICAgICAgICBnZW9tX2RlbnNpdHkoKSArCiAgICAgICAgZmFjZXRfZ3JpZChkY35yLCBsYWJlbGxlcj1sYWJlbGxlcihkYz1jKCIxIj0iMTAwJSIsICIwLjgiPSI4MCUiLCAiMC42Ij0iNjAlIiwgIjAuNCI9IjQwJSIsICIwLjIiPSIyMCUiLCAiMCI9IkNvLXRybnMgMCUiKSwgcj1jKCIwIj0iUmlibyBwcm90IGluZHggPSAwIiwgIjAuMSI9IjAuMSIsICIwLjQiPSIwLjQiLCAiMSI9IjEiKSwgbGFiZWxfcGFyc2VkKSkgKyAKICAgICAgICBsYWJzKHg9IlJlbGF0aXZlIG1lYW4gbVJOQSBjb3VudCIpICsKICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoKSArCiAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgCiAgICAgICAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLCAKICAgICAgICAgICAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmFsbFNpbUlucHV0T3V0cHV0ICU+JQogICAgZmlsdGVyKHBhcmFDb21ibyE9Im1STkFjb25zdGFudCIpICU+JQogICAgc2VsZWN0KHBhcmFDb21ibywgUk1NQywgZGMsIHIsIG1STkFEZWNSYXRlTmV5bW90aW5fc2VjKSAlPiUKICAgIG11dGF0ZShmT1JzID0gaWZlbHNlKG1STkFEZWNSYXRlTmV5bW90aW5fc2VjID49MC4wMDA5NDMxNjI4LCAiZmFzdCIsICJzbG93IikpICU+JQogICAgZ2dwbG90KGFlcyh4PVJNTUMsIGNvbG9yPWZPUnMpKSArCiAgICAgICAgZ2VvbV9kZW5zaXR5KCkgKwogICAgICAgIGZhY2V0X2dyaWQoZGN+ciwgbGFiZWxsZXI9bGFiZWxsZXIoZGM9YygiMSI9IjEwMCUiLCAiMC44Ij0iODAlIiwgIjAuNiI9IjYwJSIsICIwLjQiPSI0MCUiLCAiMC4yIj0iMjAlIiwgIjAiPSJDby10cm5zIDAlIiksIHI9YygiMCI9IlJpYm8gcHJvdCBpbmR4ID0gMCIsICIwLjEiPSIwLjEiLCAiMC40Ij0iMC40IiwgIjEiPSIxIiksIGxhYmVsX3BhcnNlZCkpICsgCiAgICAgICAgbGFicyh4PSJSZWxhdGl2ZSBtZWFuIG1STkEgY291bnQiKSArCiAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKCkgKwogICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIAogICAgICAgICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSwgCiAgICAgICAgICAgICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MTApKQpgYGAKCgoKRmlnIFMyLgpgYGB7cn0KYWxsU2ltSW5wdXRPdXRwdXQgJT4lCiAgZmlsdGVyKHBhcmFDb21ibz09ImRjXzFfcl8wIiwgT1JGIT0iWUVSMDUzQy1BIiwgbVJOQURlY1JhdGVOZXltb3Rpbl9zZWMhPTApICU+JQogIGdncGxvdChhZXMoeD1NTUMsIHk9TVZNQywgY29sb3IgPSBwYXJhQ29tYm8pKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC41KSArCiAgZ2VvbV9hYmxpbmUobGluZXR5cGU9ImRhc2hlZCIpICsKICB0aGVtZV9idygpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMyksCiAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvcj0id2hpdGUiKSwgICMgY2FuJ3QgdXNlIGVsZW1lbnRfYmxhbmsoKSBoZXJlIGJlY2F1c2UgaXQgZ2l2ZXMgZXJyb3Igd2hlbiBwMStwMgogICAgICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbihyID0gMCwgdW5pdCA9ICJwdCIpLAogICAgICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpCiAgICApICsKICAgICAgbGFicyh4ID0gJ01lYW4gb2YgbVJOQSBjb3VudCcsCiAgICAgICAgICAgeSA9ICdNZWFuIG9mIHZhcmlhbmNlIGluIG1STkEgY291bnQnKSArCiAgICAgIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lPSIiLCBsYWJlbHM9YygiZGNfMV9yXzAiPSJDby10cmFucyAxMDAlIFJpYm9Qcm90ZWN0IDAiKSwgdmFsdWVzID0gYygiIzFGNzhCNCIpKSArCiAgICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArCiAgICAgIHN0YXRfY29yKGFlcyhsYWJlbD1wYXN0ZSguLnIubGFiZWwuLiwgIHNlcCA9ICJ+YCxgfiIpKSwgbGFiZWwueC5ucGMgPSAwLjcsIGxhYmVsLnkubnBjID0gMC40LCBzaXplPTUpICsKICAgICAgc2NhbGVfeF9sb2cxMCgpICsKICAgICAgc2NhbGVfeV9sb2cxMCgpCmBgYAoKCkZpZy4gUzMKYGBge3IgZmlnLndpZHRoPTEwfQphbGxTaW1JbnB1dE91dHB1dCAlPiUKICBmaWx0ZXIocGFyYUNvbWJvIT0ibVJOQWNvbnN0YW50IiwgT1JGIT0iWUVSMDUzQy1BIiwgbVJOQURlY1JhdGVOZXltb3Rpbl9zZWMhPTApICU+JQogIGdncGxvdChhZXMoeD1NTUMsIHk9TVZNQykpICsKICBnZW9tX3BvaW50KHNpemUgPSAwLjUpICsKICBnZW9tX2FibGluZShsaW5ldHlwZT0iZGFzaGVkIikgKwogIGZhY2V0X2dyaWQoZGN+ciwgbGFiZWxsZXI9bGFiZWxsZXIoZGM9YygiMSI9IjEwMCUiLCAiMC44Ij0iODAlIiwgIjAuNiI9IjYwJSIsICIwLjQiPSI0MCUiLCAiMC4yIj0iMjAlIiwgIjAiPSJDby10cm5zIDAlIiksIHI9YygiMCI9IlJpYm8gcHJvdCBpbmR4ID0gMCIsICIwLjEiPSIwLjEiLCAiMC40Ij0iMC40IiwgIjEiPSIxIiksIGxhYmVsX3BhcnNlZCkpICsKICB0aGVtZV9idygpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMyksCiAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4ociA9IDAsIHVuaXQgPSAicHQiKSwKICAgICAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKQogICAgKSArCiAgICAgIGxhYnMoeCA9ICdNZWFuIG9mIG1STkEgY291bnQnLAogICAgICAgICAgIHkgPSAnTWVhbiBvZiB2YXJpYW5jZSBpbiBtUk5BIGNvdW50JykgKwogICAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKwogICAgICBzdGF0X2NvcihhZXMobGFiZWw9cGFzdGUoLi5yLmxhYmVsLi4sICBzZXAgPSAifmAsYH4iKSksIGxhYmVsLngubnBjID0gMC43LCBsYWJlbC55Lm5wYyA9IDAuNCwgc2l6ZT01KSArCiAgICAgIHNjYWxlX3hfbG9nMTAoKSArCiAgICAgIHNjYWxlX3lfbG9nMTAoKQpgYGAKCgoKCgoKRmlnIFM0OiBTZXF1ZW5jZSBmZWF0dXJlcyBjb3JyZWxhdGUgd2l0aCB0aGUgZmFubyBmYWN0b3Igb2YgcHJvdGVpbiBzeW50aGVzaXMgcmF0ZXMgZm9yIG1STkEgY29uc3RhbnQKYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9M30KcGxvdF9mdW4xIDwtIGZ1bmN0aW9uKHZhcjEsIHZhcjIpeyBhbGxTaW1JbnB1dE91dHB1dCU+JSAgI3ZhcjE6Ik1lYW5Qcm90ZWluU3luUmF0ZSIuLiB2YXIyOiJtUk5BY29uc3RhbnQiLCAiZGNfMV9yXzAiCiAgZmlsdGVyKHBhcmFDb21ibz09dmFyMiwgbVJOQURlY1JhdGVOZXltb3Rpbl9zZWMhPTApICU+JQogIHNlbGVjdChPUkYsIE1QU1IsIE1WUFMsIGluaVByb2JfbG9nMTAsIG1STkFhYnVuZGFuY2VfbG9nMTAsIG1STkFEZWNSYXRlTmV5bW90aW5fc2VjX2xvZzEwLCBDQUksIGdlbmVMZW5ndGhfY29kb25fbG9nMTApICU+JQogIG11dGF0ZShmYW5vX3Byb3RTeW4gPSBNVlBTL01QU1IpICU+JQogIGZpbHRlcihmYW5vX3Byb3RTeW4+MC4zKSAlPiUgICMgZmlsdGVyIG91dCB0aGUgdHdvIG91dGxpZXJzCiAgYGNvbG5hbWVzPC1gKHBhc3RlMCgiIixjKCJPUkYiLCAiTWVhblByb3RlaW5TeW5SYXRlIiwgIlZhcmlhbmNlUHJvdGVpblN5blJhdGUiLCAiaW5pUHJvYl9sb2cxMCIsICJtUk5BTGV2ZWxfbG9nMTAiLCAiRGVjUmF0ZV9sb2cxMCIsICJDQUkiLCAiZ2VuZUxlbmd0aF9sb2cxMCIsICJmYW5vX3Byb3RTeW5SYXRlIikpKSAlPiUKICBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAiZmVhdHVyZSIsIHZhbHVlc190byA9ICJmZWF0dXJlVmFscyIsICFjKE9SRixNZWFuUHJvdGVpblN5blJhdGUsIFZhcmlhbmNlUHJvdGVpblN5blJhdGUsIGZhbm9fcHJvdFN5blJhdGUpKSAlPiUKICBnZ3Bsb3QoYWVzX3N0cmluZyh4PSJmZWF0dXJlVmFscyIsIHk9dmFyMSkpICsKICAgIGdlb21fcG9pbnQoc2l6ZT0wLjUpICsKICAgIGZhY2V0X3dyYXAofmZlYXR1cmUsIHNjYWxlcz0iZnJlZSIsIG5yb3c9MSwgc3RyaXAucG9zaXRpb24gPSAiYm90dG9tIikgKwogICAgdGhlbWVfYncoKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKwogICAgc3RhdF9jb3IoYWVzKGxhYmVsPXBhc3RlKC4uci5sYWJlbC4uLCAgc2VwID0gIn5gLGB+IikpLCBsYWJlbC54Lm5wYyA9IDAuNCwgbGFiZWwueS5ucGMgPSAwLjEzLCBzaXplPTMpICsKICBsYWJzKHggPSAiIiwKICAgICAgIHkgPSB2YXIxKSArCiAgICBzY2FsZV95X2xvZzEwKCkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIpLCAgIyBjYW4ndCB1c2UgZWxlbWVudF9ibGFuaygpIGhlcmUgYmVjYXVzZSBpdCBnaXZlcyBlcnJvciB3aGVuIHAxK3AyCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgIAogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiAgICAgI3RvIHB1dCB0aGUgc3RyaXAgbGFiZWxzIGJlbG93IHgtYXhpcwopCn0KCnBsb3RfZnVuMSgiZmFub19wcm90U3luUmF0ZSIsICJtUk5BY29uc3RhbnQiKQpgYGAKCkZpZyBTNS4gCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTd9CiMgTU1EUCA9IG1STkFzIG1hcmtlZCBmb3IgZGVncmFkYXRpb24gcHJvcG9ydGlvbiBhbW9uZyBtZWFuIHRvdGFsIG1STkEKYWxsU2ltSW5wdXRPdXRwdXQgJT4lCiAgICBmaWx0ZXIocGFyYUNvbWJvID09ICJkY18xX3JfMCIsIG1STkFEZWNSYXRlTmV5bW90aW5fc2VjIT0wKSAlPiUKICAgIGdncGxvdChhZXMoeD1NTURQLCB5PVJNUFNSKSkgKwogICAgZ2VvbV9wb2ludChzaXplPTAuMSkgKwogICAgc2NhbGVfeF9sb2cxMCgpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICBsYWJzKHg9ICJQcm9wb3J0aW9uIG9mIG1STkEgbWFya2VkIGZvciBkZWNheSIsIAogICAgICAgIHkgPSAiUmVsYXRpdmUgbWVhbiBvZiBwcm90ZWluIHN5bnRoZXNpcyByYXRlcyIsIAogICAgICAgIHRpdGxlID0gIiIpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArIAogICAgc3RhdF9jb3IoYWVzKGxhYmVsPXBhc3RlKC4uci5sYWJlbC4uLCAgc2VwID0gIn5gLGB+IikpLCBsYWJlbC54Lm5wYyA9IDAuMSwgbGFiZWwueS5ucGMgPSAwLjMsIHNpemU9MykgKyAKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMykpCgpgYGAKCkZpZyBTNjogcmVsYXRpdmUgQ1YgPSBDViBvZiB0aGUgcHJvdGVpbiBzeW50aGVzaXMgcmF0ZS9DViBvZiB0aGUgbVJOQSBjb3VudApgYGB7ciBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD04fQphbGxTaW1JbnB1dE91dHB1dCAlPiUKICBmaWx0ZXIocGFyYUNvbWJvPT0iZGNfMV9yXzAiLCBtUk5BRGVjUmF0ZU5leW1vdGluX3NlYyAhPSAwLCBPUkYgIT0iWUNSMDI0Qy1CIikgJT4lICAgICMiWUNSMDI0Qy1CIiBpcyBhbiBvdXRsaWVyIHdob3NlIHJlbENWID0gMjMKICBtdXRhdGUocmVsQ1YgPSBDVlBTL0NWTUMpICU+JQogIHNlbGVjdChPUkYsIHJlbENWLCBpbmlQcm9iX2xvZzEwLCBtUk5BYWJ1bmRhbmNlX2xvZzEwLCBtUk5BRGVjUmF0ZU5leW1vdGluX3NlY19sb2cxMCwgQ0FJLCBnZW5lTGVuZ3RoX2NvZG9uX2xvZzEwKSAlPiUKICAgIGBjb2xuYW1lczwtYChwYXN0ZTAoIiIsIGMoIk9SRiIsICJSZWxhdGl2ZV9DViIsICJpbmlQcm9iX2xvZzEwIiwgIm1STkFMZXZlbF9sb2cxMCIsICJEZWNSYXRlX2xvZzEwIiwgIkNBSSIsICJnZW5lTGVuZ3RoX2xvZzEwIikpKSAlPiUKICBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAiZmVhdHVyZSIsIHZhbHVlc190byA9ICJmZWF0dXJlVmFscyIsIC1jKE9SRiwgUmVsYXRpdmVfQ1YpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9ZmVhdHVyZVZhbHMsIHkgPSBSZWxhdGl2ZV9DVikpICsKICAgIGdlb21fcG9pbnQoc2l6ZT0wLjUpICsKICAgICAgZmFjZXRfd3JhcCh+ZmVhdHVyZSwgc2NhbGVzPSJmcmVlIiwgbnJvdz0xLCBzdHJpcC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKwogICAgICBzdGF0X2NvcihhZXMobGFiZWw9cGFzdGUoLi5yLmxhYmVsLi4sICBzZXAgPSAifmAsYH4iKSksIGxhYmVsLngubnBjID0gMC4xNSwgbGFiZWwueS5ucGMgPSAwLjgsIHNpemU9MykgKwogICAgbGFicyh4PSIiLAogICAgICAgICB5ID0gIlJlbGF0aXZlIENWIikgKwogICAgICBzY2FsZV95X2xvZzEwKCkgKwogICAgICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEzKSwKICAgICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvcj0iYmxhY2siKSwgICMgY2FuJ3QgdXNlIGVsZW1lbnRfYmxhbmsoKSBoZXJlIGJlY2F1c2UgaXQgZ2l2ZXMgZXJyb3Igd2hlbiBwMStwMgogICAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCAgCiAgICAgICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikgICAgICN0byBwdXQgdGhlIHN0cmlwIGxhYmVscyBiZWxvdyB4LWF4aXMKCmBgYAoKRmlnLiBTNzogCmBgYHtyIGZpZy53aWR0aD03fQphbGxTaW1JbnB1dE91dHB1dCAlPiUKICAgIGZpbHRlcihwYXJhQ29tYm8gPT0gImRjXzFfcl8wIiwgbVJOQURlY1JhdGVOZXltb3Rpbl9zZWMhPTAsIE9SRiE9IllFUjA1M0MtQSIsIE9SRiE9IllHUjE2OUMtQSIsIE9SRiE9IllMUjEwNkMiLCBPUkYhPSJZQ1IwMjRDLUIiKSAlPiUKICAgIHNlbGVjdChNVFQsIE1NRFAsIGdlbmVMZW5ndGhfY29kb24sIFJNTURSKSAlPiUKICAgIGBjb2xuYW1lczwtYCAoYygiTWVhblRyYW5zVGltZSIsICJtUk5BTWFya2REZWNQcm9wIiwgImdlbmVMZW5ndGhfY29kb24iLCAiUmVsYXRpdmVEZWNSYXRlIikpICU+JQogICAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gImZlYXR1cmUiLCB2YWx1ZXNfdG8gPSAiZmVhdHVyZVZhbHMiLCAhZ2VuZUxlbmd0aF9jb2RvbikgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9ZmVhdHVyZVZhbHMsIHk9Z2VuZUxlbmd0aF9jb2RvbikpICsKICAgIGdlb21fcG9pbnQoc2l6ZT0wLjEpICsKICAgIGZhY2V0X3dyYXAofmZlYXR1cmUsIHNjYWxlcz0iZnJlZV94IiwgbnJvdz0xLCBzdHJpcC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgICBzY2FsZV94X2xvZzEwKCkgKwogICAgc2NhbGVfeV9sb2cxMCgpICsKICAgIGxhYnMoeD0gIiIsCiAgICAgICAgeSA9ICJHZW5lIGxlbmd0aCAoY29kb24pIiwKICAgICAgICB0aXRsZSA9ICJkY18xX3JfMCIpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArIAogICAgc3RhdF9jb3IoYWVzKGxhYmVsPXBhc3RlKC4uci5sYWJlbC4uLCAgc2VwID0gIn5gLCBgfiIpKSwgbGFiZWwueC5ucGMgPSAwLjMsIGxhYmVsLnkubnBjID0gMC4xLCBzaXplPTMpICsgCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTMpLAogICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvcj0iYmxhY2siKSwgICMgY2FuJ3QgdXNlIGVsZW1lbnRfYmxhbmsoKSBoZXJlIGJlY2F1c2UgaXQgZ2l2ZXMgZXJyb3Igd2hlbiBwMStwMgogICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgIAogICAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiKQoKYWxsU2ltSW5wdXRPdXRwdXQgJT4lCiAgICBmaWx0ZXIocGFyYUNvbWJvID09ICJkY18xX3JfMSIsIG1STkFEZWNSYXRlTmV5bW90aW5fc2VjIT0wLCBPUkYhPSJZRVIwNTNDLUEiLE9SRiE9IllHUjE2OUMtQSIsIE9SRiE9IllMUjEwNkMiLCBPUkYhPSJZQ1IwMjRDLUIiKSAlPiUKICAgIHNlbGVjdChNVFQsIE1NRFAsIGdlbmVMZW5ndGhfY29kb24sIFJNTURSKSAlPiUKICAgIGBjb2xuYW1lczwtYCAoYygiTWVhblRyYW5zVGltZSIsICJtUk5BTWFya2REZWNQcm9wIiwgImdlbmVMZW5ndGhfY29kb24iLCAiUmVsYXRpdmVEZWNSYXRlIikpICU+JQogICAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gImZlYXR1cmUiLCB2YWx1ZXNfdG8gPSAiZmVhdHVyZVZhbHMiLCAhZ2VuZUxlbmd0aF9jb2RvbikgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9ZmVhdHVyZVZhbHMsIHk9Z2VuZUxlbmd0aF9jb2RvbikpICsKICAgIGdlb21fcG9pbnQoc2l6ZT0wLjEpICsKICAgIGZhY2V0X3dyYXAofmZlYXR1cmUsIHNjYWxlcz0iZnJlZV94IiwgbnJvdz0xLCBzdHJpcC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgICBzY2FsZV94X2xvZzEwKCkgKwogICAgc2NhbGVfeV9sb2cxMCgpICsKICAgIGxhYnMoeD0gIiIsCiAgICAgICAgeSA9ICJHZW5lIGxlbmd0aCAoY29kb24pIiwKICAgICAgICB0aXRsZSA9ICJkY18xX3JfMSIpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArIAogICAgc3RhdF9jb3IoYWVzKGxhYmVsPXBhc3RlKC4uci5sYWJlbC4uLCAgc2VwID0gIn5gLGB+IikpLCBsYWJlbC54Lm5wYyA9IDAuMywgbGFiZWwueS5ucGMgPSAwLjEsIHNpemU9MykgKyAKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMyksCiAgICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIpLCAgIyBjYW4ndCB1c2UgZWxlbWVudF9ibGFuaygpIGhlcmUgYmVjYXVzZSBpdCBnaXZlcyBlcnJvciB3aGVuIHAxK3AyCiAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCAgCiAgICAgICAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIpCgoKdG1wIDwtIGFsbFNpbUlucHV0T3V0cHV0ICU+JQogICAgICAgZmlsdGVyKHBhcmFDb21ibyA9PSAiZGNfMV9yXzAiLCBtUk5BRGVjUmF0ZU5leW1vdGluX3NlYyE9MCwgT1JGIT0iWUVSMDUzQy1BIixPUkYhPSJZR1IxNjlDLUEiLCBPUkYhPSJZTFIxMDZDIixPUkYhPSJZQ1IwMjRDLUIiKSAlPiUKICAgICAgIG11dGF0ZShSRFI9TU1EUi9tUk5BRGVjUmF0ZU5leW1vdGluX3NlYykgJT4lCiAgICAgICBzZWxlY3QoUk1URSwgZ2VuZUxlbmd0aF9jb2RvbiwgUkRSKSAKc3VtbWFyeShsbShSTVRFfmdlbmVMZW5ndGhfY29kb24rUkRSLCB0bXApKQoKIyBNTURQID0gbVJOQXMgbWFya2VkIGZvciBkZWdyYWRhdGlvbiBwcm9wb3J0aW9uIGFtb25nIG1lYW4gdG90YWwgbVJOQQojIE1UVCA9IG1lYW4gdHJhbnNsYXRpb24gdGltZQphbGxTaW1JbnB1dE91dHB1dCAlPiUKICAgIGZpbHRlcihwYXJhQ29tYm8gPT0gImRjXzFfcl8wIiwgbVJOQURlY1JhdGVOZXltb3Rpbl9zZWMhPTApICU+JQogICAgZ2dwbG90KGFlcyh4PU1UVCwgeT1NTURQKSkgKwogICAgZ2VvbV9wb2ludChzaXplPTAuMSkgKwogICAgc2NhbGVfeF9sb2cxMCgpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICBsYWJzKHg9ICJNZWFuIHRyYW5zbGF0aW9uIHRpbWUiLAogICAgICAgIHkgPSAiUHJvcG9ydGlvbiBvZiBtUk5BIG1hcmtlZCBmb3IgZGVjYXkiLAogICAgICAgIHRpdGxlID0gIiIpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArIAogICAgc3RhdF9jb3IoYWVzKGxhYmVsPXBhc3RlKC4uci5sYWJlbC4uLCAgc2VwID0gIn5gLCBgfiIpKSwgbGFiZWwueC5ucGMgPSAwLjEsIGxhYmVsLnkubnBjID0gMC4zLCBzaXplPTMpICsgCiAgICB0aGVtZV9idygpIAoKCmFsbFNpbUlucHV0T3V0cHV0ICU+JQogICAgZmlsdGVyKHBhcmFDb21ibyA9PSAiZGNfMC4yX3JfMCIsIG1STkFEZWNSYXRlTmV5bW90aW5fc2VjIT0wLCBPUkYhPSJZRVIwNTNDLUEiLCBPUkYhPSJZR1IxNjlDLUEiLCBPUkYhPSJZTFIxMDZDIiwgT1JGIT0iWUNSMDI0Qy1CIikgJT4lCiAgICBzZWxlY3QoTVRULCBNTURQLCBnZW5lTGVuZ3RoX2NvZG9uLCBSTU1EUikgJT4lCiAgICBgY29sbmFtZXM8LWAgKGMoIk1lYW5UcmFuc1RpbWUiLCAibVJOQU1hcmtkRGVjUHJvcCIsICJnZW5lTGVuZ3RoX2NvZG9uIiwgIlJlbGF0aXZlRGVjUmF0ZSIpKSAlPiUKICAgIHBpdm90X2xvbmdlcihuYW1lc190byA9ICJmZWF0dXJlIiwgdmFsdWVzX3RvID0gImZlYXR1cmVWYWxzIiwgIWdlbmVMZW5ndGhfY29kb24pICU+JQogICAgZ2dwbG90KGFlcyh4PWZlYXR1cmVWYWxzLCB5PWdlbmVMZW5ndGhfY29kb24pKSArCiAgICBnZW9tX3BvaW50KHNpemU9MC4xKSArCiAgICBmYWNldF93cmFwKH5mZWF0dXJlLCBzY2FsZXM9ImZyZWVfeCIsIG5yb3c9MSwgc3RyaXAucG9zaXRpb24gPSAiYm90dG9tIikgKwogICAgc2NhbGVfeF9sb2cxMCgpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICBsYWJzKHg9ICIiLAogICAgICAgIHkgPSAiR2VuZSBsZW5ndGggKGNvZG9uKSIsCiAgICAgICAgdGl0bGUgPSAiZGNfMC4yX3JfMCIpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArIAogICAgc3RhdF9jb3IoYWVzKGxhYmVsPXBhc3RlKC4uci5sYWJlbC4uLCAgc2VwID0gIn5gLGB+IikpLCBsYWJlbC54Lm5wYyA9IDAuMywgbGFiZWwueS5ucGMgPSAwLjEsIHNpemU9MykgKyAKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMyksCiAgICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIpLCAgIyBjYW4ndCB1c2UgZWxlbWVudF9ibGFuaygpIGhlcmUgYmVjYXVzZSBpdCBnaXZlcyBlcnJvciB3aGVuIHAxK3AyCiAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCAgCiAgICAgICAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIpCgoKYWxsU2ltSW5wdXRPdXRwdXQgJT4lCiAgICBmaWx0ZXIocGFyYUNvbWJvID09ICJkY18wLjJfcl8xIiwgbVJOQURlY1JhdGVOZXltb3Rpbl9zZWMhPTAsIE9SRiE9IllFUjA1M0MtQSIsIE9SRiE9IllHUjE2OUMtQSIsIE9SRiE9IllMUjEwNkMiLCBPUkYhPSJZQ1IwMjRDLUIiKSAlPiUKICAgIHNlbGVjdChNVFQsIE1NRFAsIGdlbmVMZW5ndGhfY29kb24sIFJNTURSKSAlPiUKICAgIGBjb2xuYW1lczwtYCAoYygiTWVhblRyYW5zVGltZSIsICJtUk5BTWFya2REZWNQcm9wIiwgImdlbmVMZW5ndGhfY29kb24iLCAiUmVsYXRpdmVEZWNSYXRlIikpICU+JQogICAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gImZlYXR1cmUiLCB2YWx1ZXNfdG8gPSAiZmVhdHVyZVZhbHMiLCAhZ2VuZUxlbmd0aF9jb2RvbikgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9ZmVhdHVyZVZhbHMsIHk9Z2VuZUxlbmd0aF9jb2RvbikpICsKICAgIGdlb21fcG9pbnQoc2l6ZT0wLjEpICsKICAgIGZhY2V0X3dyYXAofmZlYXR1cmUsIHNjYWxlcz0iZnJlZV94IiwgbnJvdz0xLCBzdHJpcC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgICBzY2FsZV94X2xvZzEwKCkgKwogICAgc2NhbGVfeV9sb2cxMCgpICsKICAgIGxhYnMoeD0gIiIsCiAgICAgICAgeSA9ICJHZW5lIGxlbmd0aCAoY29kb24pIiwKICAgICAgICB0aXRsZSA9ICJkY18wLjJfcl8xIikgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpICsgCiAgICBzdGF0X2NvcihhZXMobGFiZWw9cGFzdGUoLi5yLmxhYmVsLi4sICBzZXAgPSAifmAsIGB+IikpLCBsYWJlbC54Lm5wYyA9IDAuMywgbGFiZWwueS5ucGMgPSAwLjEsIHNpemU9MykgKyAKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMyksCiAgICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIpLCAgIyBjYW4ndCB1c2UgZWxlbWVudF9ibGFuaygpIGhlcmUgYmVjYXVzZSBpdCBnaXZlcyBlcnJvciB3aGVuIHAxK3AyCiAgICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCAgCiAgICAgICAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIpCmBgYAoKCgpGaWcuIFM4CmBgYHtyIGZpZy53aWR0aD03fQphbGxTaW1JbnB1dE91dHB1dCAlPiUKICAgIGZpbHRlcihwYXJhQ29tYm8gPT0gImRjXzFfcl8wIiwgbVJOQURlY1JhdGVOZXltb3Rpbl9zZWMhPTAsIE9SRiE9IllFUjA1M0MtQSIsIE9SRiE9IllHUjE2OUMtQSIsIE9SRiE9IllMUjEwNkMiLCBPUkYhPSJZQ1IwMjRDLUIiKSAlPiUKICAgIHNlbGVjdChSTVRFLCBNVFQsIE1NRFAsIGdlbmVMZW5ndGhfY29kb24sIFJNTURSKSAlPiUKICAgIGBjb2xuYW1lczwtYCAoYygiUmVsTWVhblRFIiwgIk1lYW5UcmFuc1RpbWUiLCAibVJOQU1hcmtkRGVjUHJvcCIsICJnZW5lTGVuZ3RoX2NvZG9uIiwgIlJlbGF0aXZlRGVjUmF0ZSIpKSAlPiUKICAgIHBpdm90X2xvbmdlcihuYW1lc190byA9ICJmZWF0dXJlIiwgdmFsdWVzX3RvID0gImZlYXR1cmVWYWxzIiwgIVJlbE1lYW5URSkgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9ZmVhdHVyZVZhbHMsIHk9UmVsTWVhblRFKSkgKwogICAgZ2VvbV9wb2ludChzaXplPTAuMSkgKwogICAgZmFjZXRfd3JhcCh+ZmVhdHVyZSwgc2NhbGVzPSJmcmVlX3giLCBucm93PTEsIHN0cmlwLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICAgIHNjYWxlX3hfbG9nMTAoKSArCiAgICBzY2FsZV95X2xvZzEwKCkgKwogICAgbGFicyh4PSAiIiwKICAgICAgICB5ID0gIlJlbGF0aXZlIG1lYW4gVEUiLAogICAgICAgIHRpdGxlID0gImRjXzFfcl8wIikgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpICsgCiAgICBzdGF0X2NvcihhZXMobGFiZWw9cGFzdGUoLi5yLmxhYmVsLi4sICBzZXAgPSAifmAsIGB+IikpLCBsYWJlbC54Lm5wYyA9IDAuMywgbGFiZWwueS5ucGMgPSAwLjEsIHNpemU9MykgKyAKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMyksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT1yZWwoMC44KSksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvcj0iYmxhY2siKSwgICMgY2FuJ3QgdXNlIGVsZW1lbnRfYmxhbmsoKSBoZXJlIGJlY2F1c2UgaXQgZ2l2ZXMgZXJyb3Igd2hlbiBwMStwMgogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksICAKICAgICAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIpCgphbGxTaW1JbnB1dE91dHB1dCAlPiUKICAgIGZpbHRlcihwYXJhQ29tYm8gPT0gImRjXzAuOF9yXzAiLCBtUk5BRGVjUmF0ZU5leW1vdGluX3NlYyE9MCwgT1JGIT0iWUVSMDUzQy1BIiwgT1JGIT0iWUdSMTY5Qy1BIiwgT1JGIT0iWUxSMTA2QyIsIE9SRiE9IllDUjAyNEMtQiIpICU+JQogICAgc2VsZWN0KFJNVEUsIE1UVCwgTU1EUCwgZ2VuZUxlbmd0aF9jb2RvbiwgUk1NRFIpICU+JQogICAgYGNvbG5hbWVzPC1gIChjKCJSZWxNZWFuVEUiLCAiTWVhblRyYW5zVGltZSIsICJtUk5BTWFya2REZWNQcm9wIiwgImdlbmVMZW5ndGhfY29kb24iLCAiUmVsYXRpdmVEZWNSYXRlIikpICU+JQogICAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gImZlYXR1cmUiLCB2YWx1ZXNfdG8gPSAiZmVhdHVyZVZhbHMiLCAhUmVsTWVhblRFKSAlPiUKICAgIGdncGxvdChhZXMoeD1mZWF0dXJlVmFscywgeT1SZWxNZWFuVEUpKSArCiAgICBnZW9tX3BvaW50KHNpemU9MC4xKSArCiAgICBmYWNldF93cmFwKH5mZWF0dXJlLCBzY2FsZXM9ImZyZWVfeCIsIG5yb3c9MSwgc3RyaXAucG9zaXRpb24gPSAiYm90dG9tIikgKwogICAgc2NhbGVfeF9sb2cxMCgpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICBsYWJzKHg9ICIiLAogICAgICAgIHkgPSAiUmVsYXRpdmUgbWVhbiBURSIsCiAgICAgICAgdGl0bGUgPSAiZGNfMC44X3JfMCIpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArIAogICAgc3RhdF9jb3IoYWVzKGxhYmVsPXBhc3RlKC4uci5sYWJlbC4uLCAgc2VwID0gIn5gLCBgfiIpKSwgbGFiZWwueC5ucGMgPSAwLjMsIGxhYmVsLnkubnBjID0gMC4xLCBzaXplPTMpICsgCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTMpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9cmVsKDAuOCkpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3I9ImJsYWNrIiksICAjIGNhbid0IHVzZSBlbGVtZW50X2JsYW5rKCkgaGVyZSBiZWNhdXNlIGl0IGdpdmVzIGVycm9yIHdoZW4gcDErcDIKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCAgCiAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiKQoKYWxsU2ltSW5wdXRPdXRwdXQgJT4lCiAgICBmaWx0ZXIocGFyYUNvbWJvID09ICJkY18wLjZfcl8wIiwgbVJOQURlY1JhdGVOZXltb3Rpbl9zZWMhPTAsIE9SRiE9IllFUjA1M0MtQSIsIE9SRiE9IllHUjE2OUMtQSIsIE9SRiE9IllMUjEwNkMiLCBPUkYhPSJZQ1IwMjRDLUIiKSAlPiUKICAgIHNlbGVjdChSTVRFLCBNVFQsIE1NRFAsIGdlbmVMZW5ndGhfY29kb24sIFJNTURSKSAlPiUKICAgIGBjb2xuYW1lczwtYCAoYygiUmVsTWVhblRFIiwgIk1lYW5UcmFuc1RpbWUiLCAibVJOQU1hcmtkRGVjUHJvcCIsICJnZW5lTGVuZ3RoX2NvZG9uIiwgIlJlbGF0aXZlRGVjUmF0ZSIpKSAlPiUKICAgIHBpdm90X2xvbmdlcihuYW1lc190byA9ICJmZWF0dXJlIiwgdmFsdWVzX3RvID0gImZlYXR1cmVWYWxzIiwgIVJlbE1lYW5URSkgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9ZmVhdHVyZVZhbHMsIHk9UmVsTWVhblRFKSkgKwogICAgZ2VvbV9wb2ludChzaXplPTAuMSkgKwogICAgZmFjZXRfd3JhcCh+ZmVhdHVyZSwgc2NhbGVzPSJmcmVlX3giLCBucm93PTEsIHN0cmlwLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICAgIHNjYWxlX3hfbG9nMTAoKSArCiAgICBzY2FsZV95X2xvZzEwKCkgKwogICAgbGFicyh4PSAiIiwKICAgICAgICB5ID0gIlJlbGF0aXZlIG1lYW4gVEUiLAogICAgICAgIHRpdGxlID0gImRjXzAuNl9yXzAiKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKyAKICAgIHN0YXRfY29yKGFlcyhsYWJlbD1wYXN0ZSguLnIubGFiZWwuLiwgIHNlcCA9ICJ+YCwgYH4iKSksIGxhYmVsLngubnBjID0gMC4zLCBsYWJlbC55Lm5wYyA9IDAuMSwgc2l6ZT0zKSArIAogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEzKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPXJlbCgwLjgpKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIpLCAgIyBjYW4ndCB1c2UgZWxlbWVudF9ibGFuaygpIGhlcmUgYmVjYXVzZSBpdCBnaXZlcyBlcnJvciB3aGVuIHAxK3AyCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgIAogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikKCmFsbFNpbUlucHV0T3V0cHV0ICU+JQogICAgZmlsdGVyKHBhcmFDb21ibyA9PSAiZGNfMC40X3JfMCIsIG1STkFEZWNSYXRlTmV5bW90aW5fc2VjIT0wLCBPUkYhPSJZRVIwNTNDLUEiLCBPUkYhPSJZR1IxNjlDLUEiLCBPUkYhPSJZTFIxMDZDIiwgT1JGIT0iWUNSMDI0Qy1CIikgJT4lCiAgICBzZWxlY3QoUk1URSwgTVRULCBNTURQLCBnZW5lTGVuZ3RoX2NvZG9uLCBSTU1EUikgJT4lCiAgICBgY29sbmFtZXM8LWAgKGMoIlJlbE1lYW5URSIsICJNZWFuVHJhbnNUaW1lIiwgIm1STkFNYXJrZERlY1Byb3AiLCAiZ2VuZUxlbmd0aF9jb2RvbiIsICJSZWxhdGl2ZURlY1JhdGUiKSkgJT4lCiAgICBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAiZmVhdHVyZSIsIHZhbHVlc190byA9ICJmZWF0dXJlVmFscyIsICFSZWxNZWFuVEUpICU+JQogICAgZ2dwbG90KGFlcyh4PWZlYXR1cmVWYWxzLCB5PVJlbE1lYW5URSkpICsKICAgIGdlb21fcG9pbnQoc2l6ZT0wLjEpICsKICAgIGZhY2V0X3dyYXAofmZlYXR1cmUsIHNjYWxlcz0iZnJlZV94IiwgbnJvdz0xLHN0cmlwLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICAgIHNjYWxlX3hfbG9nMTAoKSArCiAgICBzY2FsZV95X2xvZzEwKCkgKwogICAgbGFicyh4PSAiIiwKICAgICAgICB5ID0gIlJlbGF0aXZlIG1lYW4gVEUiLAogICAgICAgIHRpdGxlID0gImRjXzAuNF9yXzAiKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKyAKICAgIHN0YXRfY29yKGFlcyhsYWJlbD1wYXN0ZSguLnIubGFiZWwuLiwgIHNlcCA9ICJ+YCwgYH4iKSksIGxhYmVsLngubnBjID0gMC4zLCBsYWJlbC55Lm5wYyA9IDAuMSwgc2l6ZT0zKSArIAogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEzKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPXJlbCgwLjgpKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIpLCAgIyBjYW4ndCB1c2UgZWxlbWVudF9ibGFuaygpIGhlcmUgYmVjYXVzZSBpdCBnaXZlcyBlcnJvciB3aGVuIHAxK3AyCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgIAogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikKCgphbGxTaW1JbnB1dE91dHB1dCAlPiUKICAgIGZpbHRlcihwYXJhQ29tYm8gPT0gImRjXzAuMl9yXzAiLCBtUk5BRGVjUmF0ZU5leW1vdGluX3NlYyE9MCwgT1JGIT0iWUVSMDUzQy1BIiwgT1JGIT0iWUdSMTY5Qy1BIiwgT1JGIT0iWUxSMTA2QyIsIE9SRiE9IllDUjAyNEMtQiIpICU+JQogICAgc2VsZWN0KFJNVEUsIE1UVCwgTU1EUCwgZ2VuZUxlbmd0aF9jb2RvbiwgUk1NRFIpICU+JQogICAgYGNvbG5hbWVzPC1gIChjKCJSZWxNZWFuVEUiLCAiTWVhblRyYW5zVGltZSIsICJtUk5BTWFya2REZWNQcm9wIiwgImdlbmVMZW5ndGhfY29kb24iLCAiUmVsYXRpdmVEZWNSYXRlIikpICU+JQogICAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gImZlYXR1cmUiLCB2YWx1ZXNfdG8gPSAiZmVhdHVyZVZhbHMiLCAhUmVsTWVhblRFKSAlPiUKICAgIGdncGxvdChhZXMoeD1mZWF0dXJlVmFscywgeT1SZWxNZWFuVEUpKSArCiAgICBnZW9tX3BvaW50KHNpemU9MC4xKSArCiAgICBmYWNldF93cmFwKH5mZWF0dXJlLCBzY2FsZXM9ImZyZWVfeCIsIG5yb3c9MSwgc3RyaXAucG9zaXRpb24gPSAiYm90dG9tIikgKwogICAgc2NhbGVfeF9sb2cxMCgpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICBsYWJzKHg9ICIiLAogICAgICAgIHkgPSAiUmVsYXRpdmUgbWVhbiBURSIsCiAgICAgICAgdGl0bGUgPSAiZGNfMC4yX3JfMCIpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArIAogICAgc3RhdF9jb3IoYWVzKGxhYmVsPXBhc3RlKC4uci5sYWJlbC4uLCAgc2VwID0gIn5gLCBgfiIpKSwgbGFiZWwueC5ucGMgPSAwLjMsIGxhYmVsLnkubnBjID0gMC4xLCBzaXplPTMpICsgCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTMpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9cmVsKDAuOCkpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3I9ImJsYWNrIiksICAjIGNhbid0IHVzZSBlbGVtZW50X2JsYW5rKCkgaGVyZSBiZWNhdXNlIGl0IGdpdmVzIGVycm9yIHdoZW4gcDErcDIKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCAgCiAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiKQoKCmFsbFNpbUlucHV0T3V0cHV0ICU+JQogICAgZmlsdGVyKHBhcmFDb21ibyA9PSAiZGNfMF9yXzAiLCBtUk5BRGVjUmF0ZU5leW1vdGluX3NlYyE9MCwgT1JGIT0iWUVSMDUzQy1BIiwgT1JGIT0iWUdSMTY5Qy1BIiwgT1JGIT0iWUxSMTA2QyIsIE9SRiE9IllDUjAyNEMtQiIpICU+JQogICAgc2VsZWN0KFJNVEUsIE1UVCwgTU1EUCwgZ2VuZUxlbmd0aF9jb2RvbiwgUk1NRFIpICU+JQogICAgYGNvbG5hbWVzPC1gIChjKCJSZWxNZWFuVEUiLCAiTWVhblRyYW5zVGltZSIsICJtUk5BTWFya2REZWNQcm9wIiwgImdlbmVMZW5ndGhfY29kb24iLCAiUmVsYXRpdmVEZWNSYXRlIikpICU+JQogICAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gImZlYXR1cmUiLCB2YWx1ZXNfdG8gPSAiZmVhdHVyZVZhbHMiLCAhUmVsTWVhblRFKSAlPiUKICAgIGdncGxvdChhZXMoeD1mZWF0dXJlVmFscywgeT1SZWxNZWFuVEUpKSArCiAgICBnZW9tX3BvaW50KHNpemU9MC4xKSArCiAgICBmYWNldF93cmFwKH5mZWF0dXJlLCBzY2FsZXM9ImZyZWVfeCIsIG5yb3c9MSwgc3RyaXAucG9zaXRpb24gPSAiYm90dG9tIikgKwogICAgc2NhbGVfeF9sb2cxMCgpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICBsYWJzKHg9ICIiLAogICAgICAgIHkgPSAiUmVsYXRpdmUgbWVhbiBURSIsCiAgICAgICAgdGl0bGUgPSAiZGNfMF9yXzAiKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKyAKICAgIHN0YXRfY29yKGFlcyhsYWJlbD1wYXN0ZSguLnIubGFiZWwuLiwgIHNlcCA9ICJ+YCwgYH4iKSksIGxhYmVsLngubnBjID0gMC4zLCBsYWJlbC55Lm5wYyA9IDAuMSwgc2l6ZT0zKSArIAogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEzKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPXJlbCgwLjgpKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIpLCAgIyBjYW4ndCB1c2UgZWxlbWVudF9ibGFuaygpIGhlcmUgYmVjYXVzZSBpdCBnaXZlcyBlcnJvciB3aGVuIHAxK3AyCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgIAogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikKCmFsbFNpbUlucHV0T3V0cHV0ICU+JQogICAgZmlsdGVyKHBhcmFDb21ibyA9PSAiZGNfMV9yXzEiLCBtUk5BRGVjUmF0ZU5leW1vdGluX3NlYyE9MCwgT1JGIT0iWUVSMDUzQy1BIiwgT1JGIT0iWUdSMTY5Qy1BIiwgT1JGIT0iWUxSMTA2QyIsIE9SRiE9IllDUjAyNEMtQiIpICU+JQogICAgc2VsZWN0KFJNVEUsIE1UVCwgTU1EUCwgZ2VuZUxlbmd0aF9jb2RvbiwgUk1NRFIpICU+JQogICAgYGNvbG5hbWVzPC1gIChjKCJSZWxNZWFuVEUiLCAiTWVhblRyYW5zVGltZSIsICJtUk5BTWFya2REZWNQcm9wIiwgImdlbmVMZW5ndGhfY29kb24iLCAiUmVsYXRpdmVEZWNSYXRlIikpICU+JQogICAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gImZlYXR1cmUiLCB2YWx1ZXNfdG8gPSAiZmVhdHVyZVZhbHMiLCAhUmVsTWVhblRFKSAlPiUKICAgIGdncGxvdChhZXMoeD1mZWF0dXJlVmFscywgeT1SZWxNZWFuVEUpKSArCiAgICBnZW9tX3BvaW50KHNpemU9MC4xKSArCiAgICBmYWNldF93cmFwKH5mZWF0dXJlLCBzY2FsZXM9ImZyZWVfeCIsIG5yb3c9MSwgc3RyaXAucG9zaXRpb24gPSAiYm90dG9tIikgKwogICAgc2NhbGVfeF9sb2cxMCgpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICBsYWJzKHg9ICIiLAogICAgICAgIHkgPSAiUmVsYXRpdmUgbWVhbiBURSIsCiAgICAgICAgdGl0bGUgPSAiZGNfMV9yXzEiKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKyAKICAgIHN0YXRfY29yKGFlcyhsYWJlbD1wYXN0ZSguLnIubGFiZWwuLiwgIHNlcCA9ICJ+YCwgYH4iKSksIGxhYmVsLngubnBjID0gMC4zLCBsYWJlbC55Lm5wYyA9IDAuMSwgc2l6ZT0zKSArIAogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEzKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPXJlbCgwLjgpKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIpLCAgIyBjYW4ndCB1c2UgZWxlbWVudF9ibGFuaygpIGhlcmUgYmVjYXVzZSBpdCBnaXZlcyBlcnJvciB3aGVuIHAxK3AyCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgIAogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikKCgphbGxTaW1JbnB1dE91dHB1dCAlPiUKICAgIGZpbHRlcihwYXJhQ29tYm8gPT0gImRjXzAuMl9yXzEiLCBtUk5BRGVjUmF0ZU5leW1vdGluX3NlYyE9MCwgT1JGIT0iWUVSMDUzQy1BIiwgT1JGIT0iWUdSMTY5Qy1BIiwgT1JGIT0iWUxSMTA2QyIsIE9SRiE9IllDUjAyNEMtQiIpICU+JQogICAgc2VsZWN0KFJNVEUsIE1UVCwgTU1EUCwgZ2VuZUxlbmd0aF9jb2RvbiwgUk1NRFIpICU+JQogICAgYGNvbG5hbWVzPC1gIChjKCJSZWxNZWFuVEUiLCAiTWVhblRyYW5zVGltZSIsICJtUk5BTWFya2REZWNQcm9wIiwgImdlbmVMZW5ndGhfY29kb24iLCAiUmVsYXRpdmVEZWNSYXRlIikpICU+JQogICAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gImZlYXR1cmUiLCB2YWx1ZXNfdG8gPSAiZmVhdHVyZVZhbHMiLCAhUmVsTWVhblRFKSAlPiUKICAgIGdncGxvdChhZXMoeD1mZWF0dXJlVmFscywgeT1SZWxNZWFuVEUpKSArCiAgICBnZW9tX3BvaW50KHNpemU9MC4xKSArCiAgICBmYWNldF93cmFwKH5mZWF0dXJlLCBzY2FsZXM9ImZyZWVfeCIsIG5yb3c9MSwgc3RyaXAucG9zaXRpb24gPSAiYm90dG9tIikgKwogICAgc2NhbGVfeF9sb2cxMCgpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICBsYWJzKHg9ICIiLAogICAgICAgIHkgPSAiUmVsYXRpdmUgbWVhbiBURSIsCiAgICAgICAgdGl0bGUgPSAiZGNfMC4yX3JfMSIpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArIAogICAgc3RhdF9jb3IoYWVzKGxhYmVsPXBhc3RlKC4uci5sYWJlbC4uLCAgc2VwID0gIn5gLCBgfiIpKSwgbGFiZWwueC5ucGMgPSAwLjMsIGxhYmVsLnkubnBjID0gMC4xLCBzaXplPTMpICsgCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTMpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9cmVsKDAuOCkpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3I9ImJsYWNrIiksICAjIGNhbid0IHVzZSBlbGVtZW50X2JsYW5rKCkgaGVyZSBiZWNhdXNlIGl0IGdpdmVzIGVycm9yIHdoZW4gcDErcDIKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLCAgCiAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiKQoKCmFsbFNpbUlucHV0T3V0cHV0ICU+JQogICAgZmlsdGVyKHBhcmFDb21ibyA9PSAiZGNfMV9yXzAiLCBtUk5BRGVjUmF0ZU5leW1vdGluX3NlYyE9MCwgT1JGIT0iWUVSMDUzQy1BIiwgT1JGIT0iWUdSMTY5Qy1BIiwgT1JGIT0iWUxSMTA2QyIsIE9SRiE9IllDUjAyNEMtQiIpICU+JQogICAgc2VsZWN0KE1NRFAsIFJNTURSKSAlPiUKICAgIGdncGxvdChhZXMoeD1NTURQLCB5PVJNTURSKSkgKwogICAgZ2VvbV9wb2ludChzaXplPTAuMSkgKwogICAgbGFicyh4PSAiTU1EUCIsCiAgICAgICAgeSA9ICJSZWxhdGl2ZSBkZWNheSByYXRlcyIsCiAgICAgICAgdGl0bGUgPSAiZGNfMV9yXzAiKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKyAKICAgIHN0YXRfY29yKGFlcyhsYWJlbD1wYXN0ZSguLnIubGFiZWwuLiwgIHNlcCA9ICJ+YCwgYH4iKSksIGxhYmVsLngubnBjID0gMC4zLCBsYWJlbC55Lm5wYyA9IDAuMSwgc2l6ZT0zKSArIAogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEzKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPXJlbCgwLjgpKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yPSJibGFjayIpLCAgIyBjYW4ndCB1c2UgZWxlbWVudF9ibGFuaygpIGhlcmUgYmVjYXVzZSBpdCBnaXZlcyBlcnJvciB3aGVuIHAxK3AyCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgIAogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikKCgphbGxTaW1JbnB1dE91dHB1dCAlPiUKICAgIGZpbHRlcihwYXJhQ29tYm8gPT0gImRjXzAuMl9yXzAiLCBtUk5BRGVjUmF0ZU5leW1vdGluX3NlYyE9MCwgT1JGIT0iWUVSMDUzQy1BIiwgT1JGIT0iWUdSMTY5Qy1BIiwgT1JGIT0iWUxSMTA2QyIsIE9SRiE9IllDUjAyNEMtQiIpICU+JQogICAgc2VsZWN0KE1NRFAsIFJNTURSKSAlPiUKICAgIGdncGxvdChhZXMoeD1NTURQLCB5PVJNTURSKSkgKwogICAgZ2VvbV9wb2ludChzaXplPTAuMSkgKwogICAgc2NhbGVfeF9sb2cxMCgpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICBsYWJzKHg9ICJNTURQIiwKICAgICAgICB5ID0gIlJlbGF0aXZlIGRlY2F5IHJhdGVzIiwKICAgICAgICB0aXRsZSA9ICJkY18wLjJfcl8wIikgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpICsgCiAgICBzdGF0X2NvcihhZXMobGFiZWw9cGFzdGUoLi5yLmxhYmVsLi4sICBzZXAgPSAifmAsIGB+IikpLCBsYWJlbC54Lm5wYyA9IDAuMywgbGFiZWwueS5ucGMgPSAwLjEsIHNpemU9MykgKyAKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMyksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT1yZWwoMC44KSksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvcj0iYmxhY2siKSwgICMgY2FuJ3QgdXNlIGVsZW1lbnRfYmxhbmsoKSBoZXJlIGJlY2F1c2UgaXQgZ2l2ZXMgZXJyb3Igd2hlbiBwMStwMgogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksICAKICAgICAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIpCmBgYAoKRmlnLiBTOQpgYGB7cn0KbGlmZXRpbWVEaXN0cmk8LSBmdW5jdGlvbihnZW5ldmVjKXsKICAgIGRmcGxvdCA8LSBjYmluZChkYy5yLmRmW2MoMjo1LCAyMjoyNSksIF0sIGRhdGEuZnJhbWUobWF0cml4KE5BLCBuY29sPSA1MDAwLCBucm93PTgqMykpKSAlPiUKICAgICAgICBtdXRhdGUoT1JGPWMocmVwKGdlbmV2ZWNbMV0sIDgpLCByZXAoZ2VuZXZlY1syXSwgOCksIHJlcChnZW5ldmVjWzNdLCA4KSkpICU+JQogICAgICAgIHJlbG9jYXRlKE9SRikKICAgIAogICAgZm9yKGkgaW4gMTo4KXtkZnBsb3RbaSwgNjo1MDA1XSA9IGFzLnZlY3RvcihoNXJlYWQoc2ltT3V0cHV0SDUsIHBhc3RlMChnZW5ldmVjWzFdLCAiL21STkFfbGlmZVRpbWVzLyIsIGRmcGxvdCRwYXJhQ29tYm9baV0pKSl9CiAgICBmb3IoaSBpbiA5OjE2KXtkZnBsb3RbaSwgNjo1MDA1XSA9IGFzLnZlY3RvcihoNXJlYWQoc2ltT3V0cHV0SDUsIHBhc3RlMChnZW5ldmVjWzJdLCAiL21STkFfbGlmZVRpbWVzLyIsIGRmcGxvdCRwYXJhQ29tYm9baV0pKSl9CiAgICBmb3IoaSBpbiAxNzoyNCl7ZGZwbG90W2ksIDY6NTAwNV0gPSBhcy52ZWN0b3IoaDVyZWFkKHNpbU91dHB1dEg1LCBwYXN0ZTAoZ2VuZXZlY1szXSwgIi9tUk5BX2xpZmVUaW1lcy8iLCBkZnBsb3QkcGFyYUNvbWJvW2ldKSkpfQogICAgCiAgICBkZnBsb3QgJT4lCiAgICAgICAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gInZhcnlpbmdQYXJhQ29tYm8iLCB2YWx1ZXNfdG8gPSAibGlmZVRpbWVzIiwgY29scyA9IDY6NTAwNSkgJT4lCiAgICAgICAgZ2dwbG90KGFlcyhsaWZlVGltZXMsIGZpbGw9ZGMpKSArCiAgICAgICAgZ2VvbV9kZW5zaXR5KGFscGhhPTAuNSwgY29sb3I9TkEpICsKICAgICAgICBmYWNldF9ncmlkKGZhY3RvcihPUkYsIGxldmVscz1nZW5ldmVjKX5yLCAKICAgICAgICAgICAgICAgICAgIGxhYmVsbGVyID0gbGFiZWxsZXIocj1jKCIwIj0iUmlibyBwcm90IGluZGV4IDAiLCAiMC4xIj0iMC4xIiwgIjAuNCI9IjAuNCIsICIxIj0iMSIpKSkgKwogICAgICAgIHNjYWxlX3hfbG9nMTAobGFiZWxzID0gc2NhbGVzOjpjb21tYV9mb3JtYXQoYWNjdXJhY3k9MUwpKSArCiAgICAgICAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lPSJDTUQgbGV2ZWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMCI9IjAiLCAiMC4yIj0iMjAlIiwgIjAuNiI9IjYwJSIsICIxIj0iMTAwJSIpKSArCiAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgbGFicyh4PXBhc3RlMCgibVJOQSBsaWZlIHRpbWUgZGlzdHJpYnV0aW9uIChsb2cxMCkiKSkgKwogICAgICAgIHRoZW1lKAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJsZWZ0IiwKICAgICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9OCkpICsKICAgICAgICBnZW9tX3ZsaW5lKGRhdGE9ZmlsdGVyKGRmcGxvdCwgT1JGPT1nZW5ldmVjWzFdKSwgYWVzKHhpbnRlcmNlcHQgPSAxL3NpbUlucHV0RmVhdHVyZXMkbVJOQURlY1JhdGVOZXltb3Rpbl9zZWNbd2hpY2goc2ltSW5wdXRGZWF0dXJlcyRPUkY9PWdlbmV2ZWNbMV0pXSksIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvcj0iZGFyayBncmV5IikgKyAjMTA0OS44NTYgPTEvc2ltSW5wdXRGZWF0dXJlcyRtUk5BRGVjUmF0ZU5leW1vdGluX3NlY1sxXSAjIDEwNDkuODU2IGlzIHRoZSBpbnB1dCBsaWZldGltZSBmb3IgWUFMMDAxQyAKICAgICAgICBnZW9tX3ZsaW5lKGRhdGE9ZmlsdGVyKGRmcGxvdCwgT1JGPT1nZW5ldmVjWzJdKSwgYWVzKHhpbnRlcmNlcHQgPSAxL3NpbUlucHV0RmVhdHVyZXMkbVJOQURlY1JhdGVOZXltb3Rpbl9zZWNbd2hpY2goc2ltSW5wdXRGZWF0dXJlcyRPUkY9PWdlbmV2ZWNbMl0pXSksIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvcj0iZGFyayBncmV5IikgKwogICAgICAgIGdlb21fdmxpbmUoZGF0YT1maWx0ZXIoZGZwbG90LCBPUkY9PWdlbmV2ZWNbM10pLCBhZXMoeGludGVyY2VwdCA9IDEvc2ltSW5wdXRGZWF0dXJlcyRtUk5BRGVjUmF0ZU5leW1vdGluX3NlY1t3aGljaChzaW1JbnB1dEZlYXR1cmVzJE9SRj09Z2VuZXZlY1szXSldKSwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPSJkYXJrIGdyZXkiKSAKICAgICAgICAjIHRoZSBhYm92ZSBsaW5lcyBhcmUgdGhlIGF2ZXJhZ2UgbGlmZSB0aW1lIGNhbGN1bGF0ZWQgZnJvbSBpbnB1dCBkZWNheSByYXRlcwp9CgpsaWZldGltZURpc3RyaShjKCJZQUwwMDFDIiwgIllLUjA3NUMiLCAiWUJSMDExQyIpKQpsaWZldGltZURpc3RyaShjKCJZTFIxMDZDIiwgIllLUjA1NEMiLCAiWUhSMDk5VyIpKSAjIGxvbmdlc3QgZ2VuZXMKbGlmZXRpbWVEaXN0cmkoYygiWUFSMDAyQy1BIiwgIllCTDA1MFciLCAiWUJSMDAzVyIpKQoKYGBgCgoKYGBge3J9CnRtcGRmIDwtIGRhdGEuZnJhbWUobGlmZXRpbWU9bG9nMTAoYXMubnVtZXJpYyhkZnBsb3RbMSwgNjo1MDA1XSkpKQp3aGljaC5tYXgoZGVuc2l0eSh0bXBkZiRsaWZldGltZSkkeSkKZGVuc2l0eSh0bXBkZiRsaWZldGltZSkkeFszODddCmdncGxvdCh0bXBkZiwgYWVzKGxpZmV0aW1lKSkgKyBnZW9tX2RlbnNpdHkoKSArIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGRlbnNpdHkodG1wZGYkbGlmZXRpbWUpJHhbMzg3XSkgCgoKYGBgCgoKRmlnLiBTCgpOT1RFUzogCk91dHB1dCBkZWNheSByYXRlID0gMS9tZWFuIGxpZmV0aW1lIDxodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9QYXJ0aWNsZV9kZWNheT4KClRvdGFsIG91dHB1dCBkZWNheSByYXRlID0gb3V0cHV0IGRlY2F5IHJhdGUgKiBvdXRwdXQgbWVhbiBtUk5BIGNvdW50CgpUb3RhbCBpbnB1dCBkZWNheSByYXRlID0gaW5wdXQgZGVjYXkgcmF0ZSAqIG1STkFhYnVuZGFuY2UKClRvdGFsIHN5bnRoZXNpcyByYXRlID0gYSBzY2FsZWQgY29uc3RhbnQKCihUaGUgYWJvdmUgcmF0ZXMgYXJlIGFsbCBnZW5lLXNwZWNpZmljKQoKU3VtbWFyeTogY2hhbmdpbmcgdG90YWwgb3V0cHV0IGRlY2F5IHJhdGUgaXMgYSByZXN1bHQgb2YgY2hhbmdpbmcgY28tdHJhbnNsYXRpb25hbCBkZWNheSBhbmQgcmlib3NvbWUgcHJvdGVjdGlvbi4gSW4gb3JkZXIgdG8gbWFpbnRhaW4gdGhlIGNvbnN0YW50IG1STkEgbGV2ZWwsIHdlIGhhdmUgdG8gc2NhbGUgdGhlIHRvdGFsIHN5bnRoZXNpcyByYXRlcyB0byBjb3VudGVyLWVmZmVjdCB0aGUgY2hhbmdpbmcgb3V0cHV0IGRlY2F5IHJhdGVzLgoKV2hlbiBjby10cmFuc2xhdGlvbmFsIGRlY2F5IGlzIGhpZ2hlciB0aGFuIDAsIHRoZXJlJ3MgYWx3YXlzIGEgc3VycGx1cyBvZiBtUk5BcyBtYXJrZWQgZm9yIGRlY2F5LCB0aGF0IGFyZSBub3QgYWNjb3VudGVkIHdoZW4gY2FsY3VsYXRpbmcgdG90YWwgZGVjYXkgcHJvYmFiaWxpdGllcyAoVGhleSdyZSBub3QgYWNjb3VudGVkIGJlY2F1c2UgdGhleSBhbHJlYWR5IGhhdmUgZGVjYXkgbWFjaGluZXJ5IGJvdW5kIHRvIHRoZW0sIHNvIGNhbm5vdCBiZSBhY2NvdW50ZWQgYWdhaW4gaW50byB0aGUgbVJOQSBwb29sIHRoYXQgY2FuIHN0aWxsIGJlIGRlZ3JhZGVkKS4gVGhlcmVmb3JlIHRoZSBzeW50aGVzaXMgcmF0ZXMgYXJlIHNjYWxlZCwgaW4gb3JkZXIgdG8gbWFpbnRhaW4gYSBzdGFibGUgcmVsYXRpdmUgbVJOQSBjb3VudCAoPSBtZWFuIG91dHB1dCBtUk5BIGNvdW50L21STkFhYnVuZGFuY2UpIGZvciBpdCB0byBiZSBjbG9zZSB0byAxIChTdXBwIEZpZyAxKS4gVGhlIG1lYW4gb3V0cHV0IG1STkEgY291bnQgZm9yIGVhY2ggZ2VuZSBpcyBhIHJlc3VsdCBvZiB0aGUgYmFsYW5jZSBiZXR3ZWVuIGl0cyBzY2FsZWQgc3ludGhlc2lzIHJhdGUgYW5kIHRvdGFsIG91dHB1dCBkZWNheSByYXRlLiBJbiBvdGhlciB3b3JkcywgdGhlIHRvdGFsIG91dHB1dCBkZWNheSByYXRlIGRpcmVjdGx5IHJlc3BvbmQgdG8gdGhlIHNjYWxlZCBzeW50aGVzaXMgcmF0ZSwgcmF0aGVyIHRoYW4gdGhlIGlucHV0IGRlY2F5IHJhdGUuIAoKVGhlIHNjYWxlZCB0b3RhbCBzeW50aGVzaXMgcmF0ZXMgYXJlIHRoZSBzbWFsbGVzdCB3aGVuIGNvLXRyYW5zbGF0aW9uYWwgZGVjYXkgPSAxMDAlLCBzbyB0aGF0IHRoZSB0b3RhbCByZWFsLXRpbWUgbVJOQSBjb3VudCBjYW4gYmUgY2xvc2UgdG8gbVJOQWFidW5kYW5jZSBldmVuIHdpdGggdGhlIGhpZ2hlc3QgYW1vdW50IG9mIG1STkFzIG1hcmtlZCBmb3IgZGVjYXkuIEluIGNvbnRyYXN0LCB0aGUgc2NhbGVkIHRvdGFsIHN5bnRoZXNpcyByYXRlcyBhcmUgdGhlIGxhcmdlc3QgYW5kIGVxdWFsIHRvIHRoZSB0b3RhbCBpbnB1dCBkZWNheSByYXRlcyB3aGVuIGNvLXRyYW5zIGRlY2F5ID0gMCUgKFN1cHAgRmlnIDJhKSwgYmVjYXVzZSB0aGVyZSBpcyAwIG1STkEgbWFya2VkIGZvciBkZWNheS4gCgpIeXBvdGhldGljYWxseSwgdGhlIHRvdGFsIG91dHB1dCBkZWNheSByYXRlcyBzaG91bGQgZXF1YWwgdG8gdGhlIHRvdGFsIHN5bnRoZXNpcyByYXRlcyBpbiBvcmRlciB0byBtYWludGFpbiB0aGUgcmVhbC10aW1lIG1STkEgY291bnQgdG8gYmUgbGFyZ2VseSB0aGUgc2FtZSBhdCB0aGUgYmVnaW5uaW5nIGFuZCB0aGUgZW5kIG9mIHRoZSBzaW11bGF0aW9uLiBJZiB1bmVxdWFsLCB0aGUgcmVhbC10aW1lIG1STkEgY291bnQgc2hvdWxkIGVpdGhlciBnbyB1cCBvciBkb3duIGFzIHRoZSBzaW11bGF0aW9uIGNvbnRpbnVlcyBjb21wYXJlZCB0byB0aGUgYmVnaW5pbmcgYW1vdW50IChpLmUuIG1STkFhYnVuZGFuY2UpLiBIb3dldmVyLCBvdXIgcmVzdWx0cyBzaG93IHRoYXQgdGhlIHRvdGFsIG91dHB1dCBkZWNheSByYXRlcyBhcmUgc2xpZ2h0bHkgbGFyZ2VyIHRoYW4gdGhlIHNjYWxlZCBzeW50aGVzaXMgcmF0ZXMgYWNyb3NzIGFsbCB0aGUgcGFyYW1ldGVyIGNvbWJvcyAoU3VwcCBGaWcgMmIuIHRoaXMgaXMgdGhlIHBhcnQgSSBkb24ndCB1bmRlcnN0YW5kLCBpcyBpdCBjb3ogdGhlIHRvdGFsIG91dHB1dCBkZWNheSByYXRlcyBpbmNsdWRlIGNvbnNpZGVyaW5nIG1STkFzTWFya2VkRm9yRGVjYXksIGJ1dCB0aGUgdG90YWwgc2NhbGVkIHN5bnRoZXNpcyByYXRlcyBkb2Vzbid0IGluY2x1ZGUgbVJOQXNNYXJrZWRGb3JEZWNheSksIGFuZCB0aGF0J3Mgc29tZWhvdyBjb250cmlidXRpbmcgdG8gdGhlIG1lYW4gcmVhbC10aW1lIG1STkEgY291bnQgYmVpbmcgZXF1YWwgdG8gbVJOQWFidW5kYW5jZSBhcyBzaG93biBpbiBTdXBwIEZpZyAxLiAKCkJlY2F1c2UgdGhlIG91dHB1dCBkZWNheSByYXRlcyBkaXJlY3RseSByZXNwb25kIHRvIHRvdGFsIHN5bnRoZXNpcyByYXRlcywgdGhleSBhcmUgaW5mbHVlbmNlZCBieSB0aGUgcGFyYSBjb21ib3MgaW4gdGhlIHNhbWUgd2F5IHRoYXQgdG90YWwgc3ludGhlc2lzIHJhdGVzIGFyZS4gVGhhdCBleHBsYWlucyB3aHkgU3VwcCBGaWcgMmMgaXMgc2ltaWxhciB0byBTdXBwIEZpZyAyYSBpbiB0aGF0IHRoZSBwZWFrcyBza2V3IHRvIHRoZSByaWdodCBhcyBjby10cmFuc2xhdGlvbmFsIGRlY2F5IHJhdGlvIGdvZXMgZG93bi4gSG93ZXZlciBpbiBTdXBwIEZpZyAyYSwgdGhlIHJhdGlvIChzY2FsZWQgc3ludGhlc2lzIHJhdGVzIFYuUy4gdG90YWwgaW5wdXQgZGVjYXkgcmF0ZXMpIHNrZXdlZCBmcm9tIGxlc3MgdGhhbiAxIHRvIDE7IHdoaWxlIGluIFN1cHAgRmlnIDJjLCB0aGUgcmF0aW8gKHRvdGFsIG91dHB1dCBkZWNheSByYXRlcyBWLlMuIHRvdGFsIGlucHV0IGRlY2F5IHJhdGVzKSBza2V3ZWQgZnJvbSAxIHRvIGxhcmdlciB0aGFuIDEuIFRoaXMgd291bGQgbWFrZSBzZW5zZSBpZiB3ZSBjYW4gZXhwbGFpbiB3aGF0J3MgZ29pbmcgb24gaW4gU3VwcCBGaWcgMmIuIAoKTWVhbndoaWxlLCB0aGUgb3V0cHV0IGRlY2F5IHJhdGVzIGZvciBzaG9ydCBnZW5lcyBhcmUgbXVjaCBsZXNzIGFmZmVjdGVkIGJ5IGRpZmZlcmVudCBjby10cmFuc2xhdGlvbmFsIGRlY2F5IHByb3BvcnRpb25zIHRoYW4gbG9uZyBnZW5lcyAoU3VwcCBGaWcgMmQpLiBUaGlzIHNob3VsZCBiZSBhIHJlZmxlY3Rpb24gdGhhdCB0aGUgdG90YWwgc3ludGhlc2lzIHJhdGVzIGZvciBzaG9ydCBnZW5lcyBhcmUgY2hhbmdpbmcgbGVzcyB3aXRoIGNoYW5naW5nIGNvLXRyYW5zbGF0aW9uYWwgZGVjYXkuCgpTdXBwIEZpZyAyYTogVGhlIHNjYWxlZCBzeW50aGVzaXMgcmF0ZXMgYXJlIHRoZSBzbWFsbGVzdCB3aGVuIGNvLXRyYW5zIGRlY2F5ID0gMTAwJSwgd2hpbGUgdGhleVxuYXJlIHRoZSBsYXJnZXN0IGFuZCBlcXVhbCB0byB0aGUgdG90YWwgaW5wdXQgZGVjYXkgcmF0ZXMgd2hlbiBjby10cmFucyBkZWNheSA9IDAlIAoKU3VwcCBGaWcgMmI6IFRvdGFsIG91dHB1dCBtUk5BIGRlY2F5IHJhdGVzIGFyZSBzbGlnaHRseSBsYXJnZXIgdGhhbiBzY2FsZWQgbVJOQSBzeW50aGVzaXMgcmF0ZXMgXG4sIGJ1dCB0aGUgcmF0aW8gc3RheXMgc3RhYmxlIHdpdGggY2hhbmdpbmcgcGFyYW1ldGVycyBcbihJIGRvbid0IHVuZGVyc3RhbmQgd2h5IHRoZSBkZWNheSByYXRlcyBoYXZlIHRvIGJlIGxhcmdlcikKClN1cHAgRmlnIDJjOiBPdXRwdXQgZGVjYXkgcmF0ZXMgcmVzcG9uZCB0byBzY2FsZWQgc3ludGhlc2lzIHJhdGVzLCB0aGVyZWZvcmUgaXRzIHJhdGlvIGFnYWluc3QgXG50b3RhbCBpbnB1dCBkZWNheSByYXRlcyBzaG93cyBzaW1pbGFyIHBhdHRlciBhcyBzY2FsZWQgc3ludGhlc2lzIHJhdGVzIGluIEZpZyAyCgpTdXBwIEZpZyAyZDogT3V0cHV0IGRlY2F5IHJhdGVzIGZvciBzaG9ydCBnZW5lcyBhcmUgbXVjaCBsZXNzIGFmZmVjdGVkIGJ5IGRpZmZlcmVudCBcbmNvLXRyYW5zbGF0aW9uYWwgZGVjYXkgdGhhbiBsb25nIGdlbmVzCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9Cm91dGNvbWVBbGxfZXhwMTEgPC0gcmVhZF9mZWF0aGVyKHBhc3RlMChiYXNlZm9sZGVyLCBleHBJRCwgIi9leHRlcm5hbERhdGEvZXhwMTFfb3V0Y29tZUFsbC5mZWF0aGVyIikpCnRtcCA8LSBvdXRjb21lQWxsX2V4cDExICU+JSAKICBmaWx0ZXIoY29tYm8gIT0ibVJOQWNvbnN0YW50IiwgdyE9MC4wMSwgdyE9MC4wNSwgdyE9MC4yKSAlPiUgCiAgc2VsZWN0KE5NTUMsIGNvbWJvLCBPUkYsIHIsIHcpICU+JSAjIE5NTUMgaW4gZXhwMTEgPSBSTU1DIGluIGV4cDAsICJub3JtYWxpemVkIiBWUyAicmVsYXRpdmUiCiAgbXV0YXRlKGRjPTEtYXMubnVtZXJpYyhyKSkgJT4lCiAgc2VsZWN0KC1yKSAlPiUgI2RlbGV0ZSB0aGUgb3JpZ2luYWwgY29sdW1uIG5hbWVkICJyIiwgaW4gZXhwMTEgdGhlIHIgbWVhbnMgQ01EIGxldmVscywgYW5kIHcgbWVhbnMgcmlib3NvbWUgcHJvdGVjdGlvbiBpbmRleAogIGRwbHlyOjpyZW5hbWUoInIiPSJ3IiwgImV4cDExY29tYm8iPSJjb21ibyIsICJSTU1DZXhwMTEiPSJOTU1DIikgJT4lICMgY2hhbmdlIHRoZSBvcmlnaW5hbCBjb2wgbmFtZWQgInciIGludG8gInIiLCBiL2MgInIiIGluIGV4cDAgbWVhbnMgcmlib3NvbWUgcHJvdGVjdGlvbiBpbmRleAogIG11dGF0ZShjb21ibz1wYXN0ZTAoImRjXyIsIGRjLCAiX3JfIiwgcikpICU+JQogIHNlbGVjdCgtZXhwMTFjb21ibywgLWRjLCAtcikKICAKCmNvbWJpbmVkUk1NQyA8LSAobCAlPiUKICAgIGZpbHRlcihjb21ibyAhPSJtUk5BY29uc3RhbnQiKSAlPiUKICAgIGxlZnRfam9pbiguLCB0bXAsIGJ5ID0gYygiY29tYm8iPSJjb21ibyIsICJPUkYiPSJPUkYiKSkpICU+JQogICAgc2VsZWN0KCJjb21ibyIsICJSTU1DIiwgIlJNTUNleHAxMSIsICJkYyIsICJyIikgJT4lCiAgICBkcGx5cjo6cmVuYW1lKCJBZnRlclNjYWxpbmciPSJSTU1DIiwgIkJlZm9yZVNjYWxpbmciPSJSTU1DZXhwMTEiKQogICAgCnN1cDEgPC0gY29tYmluZWRSTU1DICU+JQogICAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gImtleSIsIHZhbHVlc190byA9ICJSTU1DdmFsdWUiLCBjb2xzID0gMjozKSAlPiUKICAgIGdncGxvdChhZXMoeD1STU1DdmFsdWUsIGNvbG9yPWtleSkpICsKICAgICAgICBnZW9tX2RlbnNpdHkoKSArCiAgICAgICAgZmFjZXRfZ3JpZChkY35yLCBsYWJlbGxlcj1sYWJlbGxlcihkYz1jKCIwIj0iMCUiLCAiMC4yIj0iMjAlIiwgIjAuNCI9IjQwJSIsICIwLjYiPSI2MCUiLCAiMC44Ij0iODAlIiwgIjEiPSJDTUQgMTAwJSIpLCByPWMoIjAiPSJSaWJvIHByb3QgaW5keCA9IDAiLCAiMC4xIj0iMC4xIiwgIjAuNCI9IjAuNCIsICIxIj0iMSIpLCBsYWJlbF9wYXJzZWQpKSArIAogICAgICAgIGxhYnModGl0bGUgPSAiU3VwIEZpZyAxOiBtUk5BIGNvdW50cyB3aGVuIHZhcnlpbmcgYXJlIGxhcmVnZWx5IGVxdWFsIHRvIHdoZW4gdGhleSBhcmUgY29uc3RhbnQgXG5hZnRlciBzY2FsaW5nIHRoZSBtUk5BIHN5bnRoZXNpcyByYXRlcyIsIAogICAgICAgICAgICAgeD0iUmVsYXRpdmUgbWVhbiBtUk5BIGNvdW50IikgKwogICAgICAgIHNjYWxlX3lfY29udGludW91cygpICsKICAgICAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPTEsIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvcj0iZGFyayBncmV5IikgKwogICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xMCksCiAgICAgICAgICAgICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MTApKSAjIG1ha2UgdGhlIGdyaWRsaW5lIGNvbG9yIGRhcmtlcgoKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBwbG90dGluZyB0aGUgKHRvdGFsIHN5biByYXRlIGFmdGVyIHNjYWxpbmcpLyhpbnB1dCBkZWNheSByYXRlKm1STkFhYnVuZGFuY2UpIGZvciBhbGwgZ2VuZXMgZm9yIGFsbCBydyBjb21ib3MKb3V0ZGYgPC0gdGliYmxlKG1hdHJpeChOQSwgbmNvbD1ucm93KGRjLnIuZGYpLTEsIG5yb3c9NDgzOSkpCgpmb3IgKGkgaW4gMToobnJvdyhkYy5yLmRmKS0xKSkgCnsKICAgIGluZiA8LSByZWFkLnRhYmxlKHBhc3RlMChiYXNlZm9sZGVyLCBleHBJRCwgIi9pbnB1dC9hbGxHZW5lc0RlY3JFcXVhbHNTeW5yV2l0aFNjYWxpbmdfIiwgZGMuci5kZiRjb21ib1tpKzFdLCAiX1MuY2VyLm1STkEuaW5pLmFibmRjLnN5bi5kZWMiKSkKICAgIG91dGRmWywgaV0gPC0gaW5mWywgM10vKGluZlssIDRdKmluZlssIDJdKQp9Cgpjb2xuYW1lcyhvdXRkZikgPC0gZGMuci5kZiRjb21ib1syOm5yb3coZGMuci5kZildCgpzdXAyYSA8LSBvdXRkZiAlPiUKICBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAicGFyYUNvbWJvIiwgdmFsdWVzX3RvID0gInZhbHVlIiwgY29scyA9IDE6KG5yb3coZGMuci5kZiktMSkpICU+JQogIGxlZnRfam9pbiguLCBkYy5yLmRmLCBieSA9ICJwYXJhQ29tYm8iKSAlPiUKICBmaWx0ZXIodmFsdWUgIT0gMCwgcGFyYUNvbWJvPT0iZGNfMV9yXzAifHBhcmFDb21ibz09ImRjXzBfcl8wInxwYXJhQ29tYm89PSJkY18xX3JfMSJ8cGFyYUNvbWJvPT0iZGNfMF9yXzEiKSAlPiUKICBnZ3Bsb3QoYWVzKHg9dmFsdWUpKSArCiAgICBnZW9tX2RlbnNpdHkoKSArCiAgICBmYWNldF9ncmlkKGRjfnIsIGxhYmVsbGVyPWxhYmVsbGVyKGRjPWMoIjAiPSIwJSIsICIwLjIiPSIyMCUiLCAiMC40Ij0iNDAlIiwgIjAuNiI9IjYwJSIsICIwLjgiPSI4MCUiLCAiMSI9IkNNRCAxMDAlIiksIHI9YygiMCI9IlJpYm8gcHJvdCBpbmR4ID0gMCIsICIwLjEiPSIwLjEiLCAiMC40Ij0iMC40IiwgIjEiPSIxIiksIGxhYmVsX3BhcnNlZCkpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9MSwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPSJkYXJrIGdyZXkiKSArCiAgICBsYWJzKHRpdGxlID0gIiIsCiAgICAgICAgIHg9IlNjYWxlZCBzeW50aGVzaXMgcmF0ZXMvVG90YWwgaW5wdXQgZGVjYXkgcmF0ZXMiKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTkpLAogICAgICAgICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygwLjksIDEsIDEuMSwgMS4zLCAxLjUpKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBwbG90dGluZyB0aGUgKG91dHB1dCBkZWNheSByYXRlKS8oc3luIHJhdGUgYWZ0ZXIgc2NhbGluZykgZm9yIGFsbCBnZW5lcyBmb3IgYWxsIGRjL3IgcGFyYUNvbWJvcwptbWRyQWxsZ2VuZUFsbGRjciA8LSByZWFkX2ZlYXRoZXIocGFzdGUwKGJhc2Vmb2xkZXIsIGV4cElELCAiL2FuYWx5c2VzL2ZlYXRoZXJGaWxlcy9tbWRyQWxsZ2VuZUFsbGRjci5mZWF0aGVyIikpWywgMjpucm93KGRjLnIuZGYpXQptbWNBbGxnZW5lQWxsZGNyPC0gcmVhZF9mZWF0aGVyKHBhc3RlMChiYXNlZm9sZGVyLCBleHBJRCwgIi9hbmFseXNlcy9mZWF0aGVyRmlsZXMvbW1jQWxsZ2VuZUFsbGRjci5mZWF0aGVyIikpWywgMjpucm93KGRjLnIuZGYpXQp0b3RkciA8LSBtbWRyQWxsZ2VuZUFsbGRjciptbWNBbGxnZW5lQWxsZGNyCgp0b3RzeW5yIDwtIHRpYmJsZShtYXRyaXgoTkEsIG5jb2w9bnJvdyhkYy5yLmRmKS0xLCBucm93PTQ4MzkpKQpmb3IgKGkgaW4gMToobnJvdyhkYy5yLmRmKS0xKSkKewogICAgaW5mIDwtIHJlYWQudGFibGUocGFzdGUwKGJhc2Vmb2xkZXIsIGV4cElELCAiL2lucHV0L2FsbEdlbmVzRGVjckVxdWFsc1N5bnJXaXRoU2NhbGluZ18iLCBkYy5yLmRmJHBhcmFDb21ib1tpKzFdLCAiX1MuY2VyLm1STkEuaW5pLmFibmRjLnN5bi5kZWMiKSkKICAgIHRvdHN5bnJbLCBpXSA8LSBpbmZbLCAzXQp9CgpyYXRpby5kci5zeW5yIDwtIHRvdGRyL3RvdHN5bnIKY29sbmFtZXMocmF0aW8uZHIuc3lucikgPC0gZGMuci5kZiRwYXJhQ29tYm9bMjpucm93KGRjLnIuZGYpXQpyYXRpby5kci5zeW5yIDwtIHJhdGlvLmRyLnN5bnJbLTEyNzgsIF0gICAjIGdlbmUgd2l0aCB0aGUgSEwtbWluPTQ5MCBtaW4sIHRoZSBkYXRhIHBvaW50IHNrZXdzIHRoZSBzY2FsZQoKc3VwMmIgPC0gcmF0aW8uZHIuc3luciAlPiUKICBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAicGFyYUNvbWJvIiwgdmFsdWVzX3RvID0gInZhbHVlIiwgY29scyA9IDE6KG5yb3coZGMuci5kZiktMSkpICU+JQogIGxlZnRfam9pbiguLCBkYy5yLmRmLCBieSA9ICJwYXJhQ29tYm8iKSAlPiUKICBmaWx0ZXIocGFyYUNvbWJvPT0iZGNfMV9yXzAifHBhcmFDb21ibz09ImRjXzBfcl8wInxwYXJhQ29tYm89PSJkY18xX3JfMSJ8cGFyYUNvbWJvPT0iZGNfMF9yXzEiKSAlPiUgCiAgZmlsdGVyKCFpcy5uYSh2YWx1ZSkpICU+JQogIGdncGxvdChhZXMoeD12YWx1ZSkpICsKICAgIGdlb21fZGVuc2l0eSgpICsKICAgIGZhY2V0X2dyaWQoZGN+ciwgbGFiZWxsZXI9bGFiZWxsZXIoZGM9YygiMCI9IjAlIiwgIjAuMiI9IjIwJSIsICIwLjQiPSI0MCUiLCAiMC42Ij0iNjAlIiwgIjAuOCI9IjgwJSIsICIxIj0iQ01EIDEwMCUiKSwgcj1jKCIwIj0iUmlibyBwcm90IGluZHggPSAwIiwgIjAuMSI9IjAuMSIsICIwLjQiPSIwLjQiLCAiMSI9IjEiKSwgbGFiZWxfcGFyc2VkKSkgKwogICAgbGFicyh0aXRsZSA9ICIiLCAKICAgICAgICAgeD0iVG90YWwgb3V0cHV0IGRlY2F5IHJhdGVzL1NjYWxlZCBzeW50aGVzaXMgcmF0ZXMiKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPTEsIGxpbmV0eXBlPSJkYXNoZWQiLCBjb2xvcj0iZGFyayBncmV5IikgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT05KSwKICAgICAgICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTkpLAogICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpKSAKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBwbG90dGluZyB0aGUgKG91dHB1dCBkZWNheSByYXRlKnJlYWwgdGltZSBtUk5BKS8oaW5wdXQgZGVjYXkgcmF0ZSptUk5BYWJ1bmRhbmNlKWZvciBhbGwgZ2VuZXMgZm9yIGFsbCBydyBjb21ib3MKb3V0ZGYgPC0gdGliYmxlKG1hdHJpeChOQSwgbmNvbD1ucm93KGRjLnIuZGYpLTEsIG5yb3c9NDgzOSkpICNjb250YWlucyBhbGwgdGhlIHRvdGFsIGlucHV0IGRlY2F5IHJhdGVzCgpmb3IgKGkgaW4gMToobnJvdyhkYy5yLmRmKS0xKSkgICMgdGhlc2UgMTYgY29sdW1ucyBhcmUgYWxsIHRoZSBzYW1lLCBhbGwgZXF1YWwgdG8gc2ltSW5wdXRGZWF0dXJlcyRtUk5BYWJ1bmRhbmNlKnNpbUlucHV0RmVhdHVyZXMkbVJOQURlY1JhdGVOZXltb3Rpbl9zZWMKewogICAgaW5mIDwtIHJlYWQudGFibGUocGFzdGUwKGJhc2Vmb2xkZXIsIGV4cElELCAiL2lucHV0L2FsbEdlbmVzRGVjckVxdWFsc1N5bnJXaXRoU2NhbGluZ18iLCBkYy5yLmRmJHBhcmFDb21ib1tpKzFdLCAiX1MuY2VyLm1STkEuaW5pLmFibmRjLnN5bi5kZWMiKSkKICAgIG91dGRmWywgaV0gPC0gKGluZlssIDRdKmluZlssIDJdKQp9CgoKb3V0ZGYgPC0gdG90ZHIvb3V0ZGYKY29sbmFtZXMob3V0ZGYpIDwtIGRjLnIuZGYkcGFyYUNvbWJvWzI6bnJvdyhkYy5yLmRmKV0KCnN1cDJjIDwtIG91dGRmWy0xMjc4LCBdICU+JSAgICAgICAjIGdlbmUgd2l0aCB0aGUgSEwtbWluPTQ5MCBtaW4sIHRoZSBkYXRhIHBvaW50IHNrZXdzIHRoZSBzY2FsZXMKICBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAicGFyYUNvbWJvIiwgdmFsdWVzX3RvID0gInZhbHVlIiwgY29scyA9IDE6KG5yb3coZGMuci5kZiktMSkpICU+JQogIGxlZnRfam9pbiguLCBkYy5yLmRmLCBieSA9ICJwYXJhQ29tYm8iKSAlPiUKICBmaWx0ZXIodmFsdWUgIT0gMCwgcGFyYUNvbWJvPT0iZGNfMV9yXzAifHBhcmFDb21ibz09ImRjXzBfcl8wInxwYXJhQ29tYm89PSJkY18xX3JfMSJ8cGFyYUNvbWJvPT0iZGNfMF9yXzEiKSAlPiUKICBnZ3Bsb3QoYWVzKHg9dmFsdWUpKSArCiAgICBnZW9tX2RlbnNpdHkoKSArCiAgICBmYWNldF9ncmlkKGRjfnIsIGxhYmVsbGVyPWxhYmVsbGVyKGRjPWMoIjAiPSIwJSIsICIwLjIiPSIyMCUiLCAiMC40Ij0iNDAlIiwgIjAuNiI9IjYwJSIsICIwLjgiPSI4MCUiLCAiMSI9IkNNRCAxMDAlIiksIHI9YygiMCI9IlJpYm8gcHJvdCBpbmR4ID0gMCIsICIwLjEiPSIwLjEiLCAiMC40Ij0iMC40IiwgIjEiPSIxIiksIGxhYmVsX3BhcnNlZCkpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9MSwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPSJkYXJrIGdyZXkiKSArCiAgICBsYWJzKHRpdGxlID0gIiIsCiAgICAgICAgIHg9IlRvdGFsIG91dHB1dCBkZWNheSByYXRlcy9Ub3RhbCBpbnB1dCBkZWNheSByYXRlcyIpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoI3N0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTgpLAogICAgICAgICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSAgIyBoaWRlIHRoZSBncmlkIHRpdGxlCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBzbCA9IHNob3J0IG9yIGxvbmcKb3V0ZGYkc2wgPC0gcmVwKE5BLDQ4MzkpICAgCm91dGRmJHNsW3doaWNoKHNpbUlucHV0RmVhdHVyZXMkZ2VuZUxlbmd0aF9jb2Rvbj41MTIpXSA8LSAiTG9uZyIKb3V0ZGYkc2xbd2hpY2goc2ltSW5wdXRGZWF0dXJlcyRnZW5lTGVuZ3RoX2NvZG9uPD01MTIpXSA8LSAiU2hvcnQiCgoKc3VwMmQgPC0gb3V0ZGZbLTEyNzgsIF0gJT4lICAgICAgICMgdG9vayB0aGUgZ2VuZSB3aXRoIHRoZSBITC1taW49NDkwIG1pbiwgdGhlIGRhdGEgcG9pbnQgc2tld3MgdGhlIHNjYWxlcwogIHBpdm90X2xvbmdlcihuYW1lc190byA9ICJwYXJhQ29tYm8iLCB2YWx1ZXNfdG8gPSAidmFsdWUiLCBjb2xzID0gMToobnJvdyhkYy5yLmRmKS0xKSkgJT4lCiAgbGVmdF9qb2luKC4sIGRjLnIuZGYsIGJ5ID0gInBhcmFDb21ibyIpICU+JQogIGZpbHRlcih2YWx1ZSAhPSAwLCBwYXJhQ29tYm89PSJkY18xX3JfMCJ8cGFyYUNvbWJvPT0iZGNfMF9yXzAifHBhcmFDb21ibz09ImRjXzFfcl8xInxwYXJhQ29tYm89PSJkY18wX3JfMSIpICU+JQogIGdncGxvdChhZXMoeD12YWx1ZSwgY29sb3I9c2wsIGdyb3VwPXNsKSkgKwogICAgZ2VvbV9kZW5zaXR5KCkgKwogICAgZmFjZXRfZ3JpZChkY35yLCBsYWJlbGxlcj1sYWJlbGxlcihkYz1jKCIwIj0iMCUiLCAiMC4yIj0iMjAlIiwgIjAuNCI9IjQwJSIsICIwLjYiPSI2MCUiLCAiMC44Ij0iODAlIiwgIjEiPSJDTUQgMTAwJSIpLCByPWMoIjAiPSJSaWJvIHByb3QgaW5keCA9IDAiLCAiMC4xIj0iMC4xIiwgIjAuNCI9IjAuNCIsICIxIj0iMSIpLCBsYWJlbF9wYXJzZWQpKSArCiAgICBsYWJzKHRpdGxlID0gIiIsCiAgICAgICAgIHg9IlRvdGFsIG91dHB1dCBkZWNheSByYXRlcy9Ub3RhbCBpbnB1dCBkZWNheSByYXRlcyIpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9MSwgbGluZXR5cGU9ImRhc2hlZCIsIGNvbG9yPSJkYXJrIGdyZXkiKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKAogICAgICAgICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9OSksCiAgICAgICAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuOSwgMC45NSksCiAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBsZWdlbmQuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksICMgY2hhbmdlIHRoZSBsZWdlbmQgYmFja2dyb3VuZCB0byB0cmFuc3BhcmVudAogICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUsICJsaW5lIikpICsKICAgIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWUgPSAiIiwgbGFiZWxzID0gKQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpzdXAxCgpzdXAyIDwtIChzdXAyYXxzdXAyYikvKHN1cDJjfHN1cDJkKQpzdXAyICsgcGxvdF9hbm5vdGF0aW9uKAogICB0aXRsZSA9ICdTdXBwIEZpZyAyLicsCiAgIyBzdWJ0aXRsZSA9ICdTdXBwIEZpZyAyLicsCiAgIyBjYXB0aW9uID0gJ0hlbGxvJywgICAjIHRoaXMgb25lIGFwcGVhcnMgYXQgdGhlIGJvdHRvbQogIHRhZ19sZXZlbHMgPSAnYScKKQoKCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnRvdC5pbi5kciA8LSB0aWJibGUobWF0cml4KE5BLCBuY29sPW5yb3coZGMuci5kZiktMSwgbnJvdz00ODM5KSkgI2NvbnRhaW5zIGFsbCB0aGUgdG90YWwgaW5wdXQgZGVjYXkgcmF0ZXMKCmZvciAoaSBpbiAxOihucm93KGRjLnIuZGYpLTEpKSAgIyB0aGVzZSAxNiBjb2x1bW5zIGFyZSBhbGwgdGhlIHNhbWUsIGFsbCBlcXVhbCB0byBzaW1JbnB1dEZlYXR1cmVzJG1STkFhYnVuZGFuY2Uqc2ltSW5wdXRGZWF0dXJlcyRtUk5BRGVjUmF0ZU5leW1vdGluX3NlYwp7CiAgICBpbmYgPC0gcmVhZC50YWJsZShwYXN0ZTAoYmFzZWZvbGRlciwgZXhwSUQsICIvaW5wdXQvYWxsR2VuZXNEZWNyRXF1YWxzU3lucldpdGhTY2FsaW5nXyIsIGRjLnIuZGYkcGFyYUNvbWJvW2krMV0sICJfUy5jZXIubVJOQS5pbmkuYWJuZGMuc3luLmRlYyIpKQogICAgdG90LmluLmRyWywgaV0gPC0gKGluZlssIDRdKmluZlssIDJdKQp9CgptbWRyQWxsZ2VuZUFsbGRjciA8LSByZWFkX2ZlYXRoZXIocGFzdGUwKGJhc2Vmb2xkZXIsIGV4cElELCAiL2FuYWx5c2VzL2ZlYXRoZXJGaWxlcy9tbWRyQWxsZ2VuZUFsbGRjci5mZWF0aGVyIikpWywgMjpucm93KGRjLnIuZGYpXQptbWNBbGxnZW5lQWxsZGNyPC0gcmVhZF9mZWF0aGVyKHBhc3RlMChiYXNlZm9sZGVyLCBleHBJRCwgIi9hbmFseXNlcy9mZWF0aGVyRmlsZXMvbW1jQWxsZ2VuZUFsbGRjci5mZWF0aGVyIikpWywgMjpucm93KGRjLnIuZGYpXQp0b3Qub3V0LmRyIDwtIG1tZHJBbGxnZW5lQWxsZGNyKm1tY0FsbGdlbmVBbGxkY3IKCm91dGRmIDwtIHRvdC5vdXQuZHIvdG90LmluLmRyCmNvbG5hbWVzKG91dGRmKSA8LSBkYy5yLmRmJHBhcmFDb21ib1syOm5yb3coZGMuci5kZildCgpvdXRkZlstMTI3OCwgXSAlPiUgICAgICAgIyBnZW5lIHdpdGggdGhlIEhMLW1pbj00OTAgbWluLCB0aGUgZGF0YSBwb2ludCBza2V3cyB0aGUgc2NhbGVzCiAgcGl2b3RfbG9uZ2VyKG5hbWVzX3RvID0gInBhcmFDb21ibyIsIHZhbHVlc190byA9ICJvdXRJbkRyUmF0aW8iLCBjb2xzID0gMToobnJvdyhkYy5yLmRmKS0xKSkgJT4lCiAgbGVmdF9qb2luKC4sIGRjLnIuZGYsIGJ5ID0gInBhcmFDb21ibyIpICU+JQogIGZpbHRlcihvdXRJbkRyUmF0aW8gIT0gMCkgJT4lCiAgbXV0YXRlKGRjX2ZjdD1mYWN0b3IoZGMsIGxldmVscz1jKCIxIiwgIjAuOCIsICIwLjYiLCAiMC40IiwgIjAuMiIsICIwIikpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9ZGNfZmN0LCB5PW91dEluRHJSYXRpbywgZmlsbD1yKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNpemUgPSAwLjEpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PW1lZGlhbihhcy5udW1lcmljKHVubGlzdChvdXRkZiAlPiVzZWxlY3QoZGNfMV9yXzApKSlbLTEyNzhdLCBuYS5ybSA9IFRSVUUpKSwgCiAgICAgICAgICAgICBjb2xvcj0icmVkIiwgbGluZXR5cGU9ImRhc2hlZCIpICsKICB0aGVtZV9idygpICsKICBsYWJzKHg9IkNNRCBsZXZlbCIsCiAgICAgICB5PSJSYXRpbyBiZXR3ZWVuIHRvdGFsIG91dHB1dC9pbnB1dCBkZWNheSByYXRlcyIpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz1jKCIxIj0iMTAwJSIsICIwLjgiPSI4MCUiLCAiMC42Ij0iNjAlIiwgIjAuNCI9IjQwJSIsICIwLjIiPSIyMCUiLCAiMCI9IjAiKSkgKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZSA9ICJSaWJvc29tZVxucHJvdCBpbmRleCIpICsKICB0aGVtZSgKICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIgogICkKCgojIyMjIyMjIyMjIyMjIwpvdXRkZiA8LSB0aWJibGUobWF0cml4KE5BLCBuY29sPW5yb3coZGMuci5kZiktMSwgbnJvdz00ODM5KSkgI2NvbnRhaW5zIGFsbCB0aGUgdG90YWwgaW5wdXQgZGVjYXkgcmF0ZXMKCmZvciAoaSBpbiAxOihucm93KGRjLnIuZGYpLTEpKSAgIyB0aGVzZSAxNiBjb2x1bW5zIGFyZSBhbGwgdGhlIHNhbWUsIGFsbCBlcXVhbCB0byBzaW1JbnB1dEZlYXR1cmVzJG1STkFhYnVuZGFuY2Uqc2ltSW5wdXRGZWF0dXJlcyRtUk5BRGVjUmF0ZU5leW1vdGluX3NlYwp7CiAgICBpbmYgPC0gcmVhZC50YWJsZShwYXN0ZTAoYmFzZWZvbGRlciwgZXhwSUQsICIvaW5wdXQvYWxsR2VuZXNEZWNyRXF1YWxzU3lucldpdGhTY2FsaW5nXyIsIGRjLnIuZGYkcGFyYUNvbWJvW2krMV0sICJfUy5jZXIubVJOQS5pbmkuYWJuZGMuc3luLmRlYyIpKQogICAgb3V0ZGZbLCBpXSA8LSAoaW5mWywgNF0qaW5mWywgMl0pCn0KCgpvdXRkZiA8LSB0b3Rkci9vdXRkZgpjb2xuYW1lcyhvdXRkZikgPC0gZGMuci5kZiRwYXJhQ29tYm9bMjpucm93KGRjLnIuZGYpXQoKCm91dGRmICU+JQogIG11dGF0ZShtUk5BYWJ1bmRhbmNlPXNpbUlucHV0RmVhdHVyZXMkbVJOQWFidW5kYW5jZSwgbVJOQURlY1JhdGVOZXltb3Rpbl9zZWM9c2ltSW5wdXRGZWF0dXJlcyRtUk5BRGVjUmF0ZU5leW1vdGluX3NlYywgT1JGPXNpbUlucHV0RmVhdHVyZXMkT1JGKSAlPiUKICBwaXZvdF9sb25nZXIobmFtZXNfdG8gPSAicGFyYUNvbWJvIiwgdmFsdWVzX3RvID0gInJhdGlvVmFsIiwgY29scyA9ICFjKG1STkFhYnVuZGFuY2UsIG1STkFEZWNSYXRlTmV5bW90aW5fc2VjLCBPUkYpKSAlPiUKICBmaWx0ZXIocGFyYUNvbWJvPT0iZGNfMF9yXzEiLCBtUk5BRGVjUmF0ZU5leW1vdGluX3NlYyE9MCwgT1JGIT0iWUVSMDUzQy1BIikgJT4lCiAgZ2dwbG90KGFlcyh4PW1STkFhYnVuZGFuY2UsIHk9cmF0aW9WYWwpKSArCiAgZ2VvbV9wb2ludCgpICsKICB0aGVtZV9idygpICsKICBzY2FsZV94X2xvZzEwKCkKICAKYGBgCgoKCgoKCgoKCkZpZy4gUwpgYGB7cn0KbCAlPiUKICBmaWx0ZXIocGFyYUNvbWJvPT0iZGNfMV9yXzAiLCBtUk5BRGVjUmF0ZU5leW1vdGluX3NlYyE9MCwgT1JGIT0iWUNSMDI0Qy1CIiwgbVJOQWFidW5kYW5jZSE9MSkgJT4lCiAgbXV0YXRlKHJlbGF0aXZlRmFubyA9IFJNVlBTL1JNUFNSKSAlPiUKICBnZ3Bsb3QoYWVzKHg9Uk1QU1IsIHk9cmVsYXRpdmVGYW5vKSkgKwogIGdlb21fcG9pbnQoc2l6ZT0wLjEpICsKICBzY2FsZV94X2xvZzEwKCkgKwogIHNjYWxlX3lfbG9nMTAoKSArCiAgICAgIGxhYnMoeD0gIlJlYWx0aXZlIG1lYW4gcHJvdGVpbiBzeW50aGVzaXMgcmF0ZSIsCiAgICAgICAgeSA9ICJSZWxhdGl2ZSBmYW5vIGZhY3RvciBpbiBwcm90ZWluIHN5bnRoZXNpcyByYXRlIiwKICAgICAgICB0aXRsZSA9ICIiKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKyAKICAgIHN0YXRfY29yKGFlcyhsYWJlbD1wYXN0ZSguLnIubGFiZWwuLiwgc2VwID0gIn5gLCBgfiIpKSwgbGFiZWwueC5ucGMgPSAwLjEsIGxhYmVsLnkubnBjID0gMC4zLCBzaXplPTMpICsgCiAgICB0aGVtZV9idygpIAoKCgpgYGAKCgpgYGB7cn0KYWxsU2ltSW5wdXRPdXRwdXQgJT4lCiAgICBmaWx0ZXIocGFyYUNvbWJvID09ICJkY18xX3JfMCIsIG1STkFEZWNSYXRlTmV5bW90aW5fc2VjIT0wLCBPUkYhPSJZQ1IwMjRDLUIiLCBtUk5BYWJ1bmRhbmNlIT0xKSAlPiUKICAgIGdncGxvdChhZXMoeD1NUkQsIHk9Uk1WVEUpKSArCiAgICBnZW9tX3BvaW50KHNpemU9MC4xKSArCiAgICBzY2FsZV94X2xvZzEwKCkgKwogICAgc2NhbGVfeV9sb2cxMCgpICsKICAgIGxhYnMoeD0gIk1lYW4gcmlib3NvbWUgZGVuc2l0eSIsCiAgICAgICAgeSA9ICJSZWxhdGl2ZSBtZWFuIG9mIHZhcmlhbmNlIGluIHRyYW5zbGF0aW9uIGVmZmljaWVuY3kiLAogICAgICAgIHRpdGxlID0gIiIpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArIAogICAgc3RhdF9jb3IoYWVzKGxhYmVsPXBhc3RlKC4uci5sYWJlbC4uLCBzZXAgPSAifmAsIGB+IikpLCBsYWJlbC54Lm5wYyA9IDAuMSwgbGFiZWwueS5ucGMgPSAwLjMsIHNpemU9MykgKyAKICAgIHRoZW1lX2J3KCkgCgoKYWxsU2ltSW5wdXRPdXRwdXQgJT4lCiAgICBmaWx0ZXIocGFyYUNvbWJvID09ICJkY18xX3JfMCIsIG1STkFEZWNSYXRlTmV5bW90aW5fc2VjIT0wLCBPUkYhPSJZQ1IwMjRDLUIiLCBtUk5BYWJ1bmRhbmNlIT0xKSAlPiUKICAgIGdncGxvdChhZXMoeD1NTURQLCB5PW1STkFEZWNSYXRlTmV5bW90aW5fc2VjKSkgKwogICAgZ2VvbV9wb2ludChzaXplPTAuMSkgKwogICAgc2NhbGVfeF9sb2cxMCgpICsKICAgIHNjYWxlX3lfbG9nMTAoKSArCiAgICBsYWJzKHg9ICJNZWFuIHJpYm9zb21lIGRlbnNpdHkiLAogICAgICAgIHkgPSAiUmVsYXRpdmUgbWVhbiBvZiB2YXJpYW5jZSBpbiB0cmFuc2xhdGlvbiBlZmZpY2llbmN5IiwKICAgICAgICB0aXRsZSA9ICIiKSArCiAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIikgKyAKICAgIHN0YXRfY29yKGFlcyhsYWJlbD1wYXN0ZSguLnIubGFiZWwuLiwgIHNlcCA9ICJ+YCwgYH4iKSksIGxhYmVsLngubnBjID0gMC4xLCBsYWJlbC55Lm5wYyA9IDAuMywgc2l6ZT0zKSArIAogICAgdGhlbWVfYncoKSAKCmBgYAoKCgpGaWd1cmUgUy4KYGBge3J9CgojIGNhbGN1bGF0aW5nIHRoZSBtZWFuIG51bWJlciBvZiBmcmVlIHJpYm9zIChhdmVyYWdlZCBvdmVyIHNpbXVUaW1lIGFuZCB0ZWNoUmVwcykgZm9yIGFsbCBkYy5yLnBhcmFDb21ib3MKIyBSTUZSID0gcmVsYXRpdmUgbWVhbiBmcmVlIHJpYm8KbWZyIDwtIGMoKSAKZm9yKGkgaW4gMTpucm93KGRjLnIuZGYpKSAjIGxvb3AgdGhyb3VnaCB0aGUgZGMvciBwYXJhbWV0ZXIgc3BhY2UgdG8gY2FsY3VsYXRlIHRoZSBtZWFuIGZyZWUgcmlibwp7CiAgICAjIGZyZWVfcmlibyBhdmVyYWdlZCBieSBzaW11VGltZSBhbmQgdGVjaFJlcHMKICAgIG1mciA8LSBjKG1mciwgbWVhbihoNXJlYWQoc2ltT3V0cHV0SDUsIHBhc3RlKCJmcmVlX3JpYm9fdFJOQV9wZXJNaW4iLCBkYy5yLmRmJHBhcmFDb21ib1tpXSwgInJpYm8iLCBzZXA9Ii8iKSksIG5hLnJtID0gVFJVRSkpCiAgICAjIHNldCBuYS5ybT1UIGJlY2F1c2UgaW4gcmVwIDY2IGFnYWluIHRoZXJlJ3MgYW4gTkEgYXQgdGhlIGxhc3QgbWludXRlLCB3aGljaCB3b24ndCBhZmZlY3QgdGhlIG92ZXJhbGwgbWVhbgp9CgpybWZyIDwtIG1mci9tZnJbMV0Kcm1mcl9kZiA8LSBkYXRhLmZyYW1lKFJNRlIgPSBybWZyLAogICAgICAgICAgICAgICAgICAgICAgTUZSID0gbWZyLAogICAgICAgICAgICAgICAgICAgICAgcGFyYSA9IGRjLnIuZGYkcGFyYSkKCiMgcm1mcl9kZiBjYW4gYmUgZm91bmQgaW4gZXhwMF9wcmVwUGxvdHMuUm1kCnJtZnJfZGYgJT4lCiAgbGVmdF9qb2luKC4sIGRjLnIuZGYsIGJ5ID0icGFyYSIpICU+JQogIGZpbHRlcihwYXJhQ29tYm8gIT0ibVJOQWNvbnN0YW50IikgJT4lCiAgc2VsZWN0KFJNRlIsIGRjLCByKSAlPiUKICBzcHJlYWQoZGMsIFJNRlIpICU+JQogIHNlbGVjdCgtcikgJT4lCiAgY29sTWVhbnMoKSAlPiUKICB0aWJibGUoKSAlPiUgCiAgbXV0YXRlKGRjPWFzLmNoYXJhY3RlcihzZXEoMCwgMSwgYnk9MC4yKSkpICU+JQogIGBjb2xuYW1lczwtYChjKCJSTUZSbWVhbkJ5Q29UcmFucyIsICJkYyIpKSAlPiUKICAgIG11dGF0ZShjb3RyYW5zID0gcGFzdGUwKGFzLm51bWVyaWMoZGMpKjEwMCwgIiUiKSkgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9Y290cmFucywgeT1STUZSbWVhbkJ5Q29UcmFucykpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICB0aGVtZV9idygpICsKICAgIGxhYnMgKCB0aXRsZSA9ICIiLAogICAgICAgICAgICAgICAgeCA9IkNvLXRyYW5zbGF0aW9uYWwgZGVjYXkgcHJvcG9ydGlvbiIsCiAgICAgICAgICAgICAgICB5ID0gIk1lYW4gZnJlZSByaWJvc29tZXMgKHJlbGF0aXZlIHRvIG1STkEgY29uc3RhbnQpIikgKwogICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMpLAogICAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCIxMDAlIiwgIjgwJSIsICI2MCUiLCAiNDAlIiwgIjIwJSIsICIwJSIpKQogIApgYGAKCmBgYHtyfQoKbWFrZV9oZWF0bWFwIDwtIGZ1bmN0aW9uKG9yZGVyVmFyLCBvdXRwdXRWYXIsIGxlZ2VuZE5hbWUsIHRpdGxlWSkKewogICAgY29sb3J2ZWMgPC0gcXVhbnRpbGUoYWxsU2ltSW5wdXRPdXRwdXRbW291dHB1dFZhcl1dKQogIAogICAgdG1wIDwtIChhbGxTaW1JbnB1dE91dHB1dCU+JWZpbHRlcihwYXJhQ29tYm89PSJkY18xX3JfMCIpKVssIGMoIk9SRiIsIG9yZGVyVmFyKV0KICAgIHRtcCA8LSB0bXBbb3JkZXIodG1wWywgMl0sIGRlY3JlYXNpbmcgPSBUKSwgXQogICAgdG1wJG5ld2lkX2RjMXIwIDwtIDE6NDgzOQogICAgCiAgICBhbGxTaW1JbnB1dE91dHB1dCAlPiUgCiAgICAgICAgZmlsdGVyKHBhcmFDb21ibyE9Im1STkFjb25zdGFudCIpICU+JSAKICAgICAgICBsZWZ0X2pvaW4oLiwgdG1wWywgYygiT1JGIiwgIm5ld2lkX2RjMXIwIildLCBieSA9ICJPUkYiKSAlPiUKICAgICAgICBtdXRhdGUoZGNfZmN0PWZhY3RvcihkYywgbGV2ZWxzPWMoIjEiLCAiMC44IiwgIjAuNiIsICIwLjQiLCAiMC4yIiwgIjAiKSkpICU+JQogICAgICAgIGdncGxvdChhZXNfc3RyaW5nKHggPSAiciIsIAogICAgICAgICAgICAgICAgICAgeSA9ICJmYWN0b3IobmV3aWRfZGMxcjApIiwKICAgICAgICAgICAgICAgICAgIGZpbGwgPSBvdXRwdXRWYXIpKSArCiAgICAgICAgZ2VvbV9yYXN0ZXIoKSArCiAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3VycyA9IGMoIiMzNzdlYjgiLCAid2hpdGUiLCAiI2U0MWExYyIpLCAgICMgYmx1ZSB3aGl0ZSByZWQKICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gc2NhbGVzOjpyZXNjYWxlKGNvbG9ydmVjKSwgbmFtZT1sZWdlbmROYW1lKSArCiAgICAgICAgZmFjZXRfd3JhcCh+ZGNfZmN0LCBucm93PTEsIGxhYmVsbGVyPWxhYmVsbGVyKGRjX2ZjdD1jKCIxIj0iQ28tdHJhbnMgMTAwJSIsICIwLjgiPSI4MCUiLCAiMC42Ij0iNjAlIiwgIjAuNCI9IjQwJSIsICIwLjIiPSIyMCUiLCAiMCI9IjAiKSkpICsgCiAgICAgICAgbGFicyAoIHggPSAiUmlib3NvbWUgcHJvdGVjdGlvbiBpbmRleCByIiwKICAgICAgICAgICAgICAgeSA9IHRpdGxlWSwKICAgICAgICAgICAgICAgdGl0bGUgPSAiIikgKwogICAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwKICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLCAgIyByZW1vdmUgdGhlIGdyaWQgbGluZXMgaW4gZmFjZXRfZ3JpZAogICAgICAgICAgICAgIHBhbmVsLnNwYWNpbmc9dW5pdCgwLCAibGluZXMiKSkgKyAgICMgcmVzZXQgdGhlIHNwYWNpbmcgYmV0d2VlbiBmYWNldHMKICAgICAgICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAxLCBiYXJoZWlnaHQgPSAxMCkpICsKICAgICAgICAgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQgPSBjKDAsIDApKSAjIHJlbW92ZSB0aGUgZXh0cmEgc3BhY2UgYmV5b25kIHhsaW0KCn0KCgpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9OH0KIyAxc3QgdmFyPSB0aGUgdmFyaWFibGUgY29sdW1uIHRoZSBzb3J0aW5nIGlzIGJhc2VkIG9uCiMgMm5kIHZhcj0gdGhlIHZhcmlhYmxlIGNvbHVtbiBwcmVzZW50ZWQgaW4gdGhlIGhlYXRtYXAKIyAzcmQgdmFyPSB0aGUgbGVnZW5kIHRleHQKIyA0dGggdmFyPSB5LWF4aXMgdGl0bGUKCm1ha2VfaGVhdG1hcCgiUk1URSIsICJSTVRFIiwgIlJlbGF0aXZlXG5tZWFuIHRyYW5zbGF0aW9uXG5lZmZpY2llbmN5IiwgIkdlbmVzIHJhbmtlZCBieSB0aGUgZmlyc3QgY29sdW1uIikKbWFrZV9oZWF0bWFwKCJSTVZURSIsICJSTVZURSIsICJSZWxhdGl2ZSBtZWFuXG5vZiB0aGUgdmFyaWFuY2VcbmluIHRyYW5zbGF0aW9uXG5lZmZpY2llbmN5IiwgIkdlbmVzIHJhbmtlZCBieSB0aGUgZmlyc3QgY29sdW1uIikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgYWRkIGEgcGxvdCBmb3IgbVJOQXMgbWFya2VkIGZvciBkZWNheQpjb2xvcnZlYyA8LSBxdWFudGlsZSgoYWxsU2ltSW5wdXRPdXRwdXQlPiUgZmlsdGVyKHBhcmFDb21ibyE9Im1STkFjb25zdGFudCIsIG1STkFEZWNSYXRlTmV5bW90aW5fc2VjIT0wLCBPUkYhPSJZRVIwNTNDLUEiKSkkTU1EUCkKCnRtcCA8LSAoYWxsU2ltSW5wdXRPdXRwdXQlPiVmaWx0ZXIocGFyYUNvbWJvPT0iZGNfMV9yXzAiKSlbLCBjKCJPUkYiLCAiUk1URSIpXQp0bXAgPC0gdG1wW29yZGVyKHRtcFssIDJdLCBkZWNyZWFzaW5nID0gVCksIF0KdG1wJG5ld2lkX2RjMXIwIDwtIDE6NDgzOQoKYWxsU2ltSW5wdXRPdXRwdXQgJT4lIAogICAgbXV0YXRlKGRjX2ZjdD1mYWN0b3IoZGMsIGxldmVscz1jKCIxIiwgIjAuOCIsICIwLjYiLCAiMC40IiwgIjAuMiIsICIwIikpKSAlPiUKICAgIGZpbHRlcihwYXJhQ29tYm8hPSJtUk5BY29uc3RhbnQiLCBtUk5BRGVjUmF0ZU5leW1vdGluX3NlYyE9MCwgT1JGIT0iWUVSMDUzQy1BIiwgZGMhPTApICU+JSAKICAgIGxlZnRfam9pbiguLCB0bXBbLCBjKCJPUkYiLCAibmV3aWRfZGMxcjAiKV0sIGJ5ID0gIk9SRiIpICU+JQogICAgZ2dwbG90KGFlcyh4ID0gciwgCiAgICAgICAgICAgICAgIHkgPSBmYWN0b3IobmV3aWRfZGMxcjApLAogICAgICAgICAgICAgICAjeSA9IGFzLmNoYXJhY3RlcihuZXdpZF9nZW5lTGVuZ3RoX2NvZG9uKSwgICAjIGdlbmVzIGFyZSBzb3J0ZWQgYnkgZ2VuZUxlbmd0aF9jb2RvbiB3aXRoaW4gZWFjaCBncm91cAogICAgICAgICAgICAgICBmaWxsID0gTU1EUCkpICsKICAgIGdlb21fcmFzdGVyKCkgKwogICAgdGhlbWVfYncoKSArCiAgICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvdXJzID0gYygiIzM3N2ViOCIsICJ3aGl0ZSIsICIjZTQxYTFjIiksICAgIyBibHVlIHdoaXRlIHJlZAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IHNjYWxlczo6cmVzY2FsZShjb2xvcnZlYyksIG5hbWU9Im1STkFzIG1hcmtlZFxuZm9yIGRlY2F5IHJhdGlvIikgKwogICAgZmFjZXRfd3JhcCh+ZGNfZmN0LCBucm93PTEsIGxhYmVsbGVyPWxhYmVsbGVyKGRjX2ZjdD1jKCIxIj0iQ28tdHJhbnMgMTAwJSIsICIwLjgiPSI4MCUiLCAiMC42Ij0iNjAlIiwgIjAuNCI9IjQwJSIsICIwLjIiPSIyMCUiLCAiMCI9IjAlIikpKSArCiAgICBsYWJzICggeCA9ICJSaWJvc29tZSBwcm90ZWN0aW9uIGluZGV4IHciLAogICAgICAgICAgIHkgPSAiR2VuZXMgcmFua2VkIGJ5IHRoZSBmaXJzdCBjb2x1bW4gaW4gdHJhbnNsYXRpb24gZWZmaWNpZW5jeSBwbG90IiwKICAgICAgICAgICB0aXRsZSA9ICIiKSArCiAgICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCksCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9cmVsKDEuNSkpLAogICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksICAjIHJlbW92ZSB0aGUgZ3JpZCBsaW5lcyBpbiBmYWNldF9ncmlkCiAgICAgICAgICBwYW5lbC5zcGFjaW5nPXVuaXQoMCwgImxpbmVzIikpICsgICAjIHJlc2V0IHRoZSBzcGFjaW5nIGJldHdlZW4gZmFjZXRzCiAgICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSAxLCBiYXJoZWlnaHQgPSAxMCkpICsKICAgICBzY2FsZV94X2Rpc2NyZXRlKGV4cGFuZCA9IGMoMCwgMCkpICMgcmVtb3ZlIHRoZSBleHRyYSBzcGFjZSBiZXlvbmQgeGxpbQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgYWRkIGFub3RoZXIgcGxvdCBmb3IgbVJOQXMgbWFya2VkIGZvciBkZWNheQpjb2xvcnZlYyA8LSBxdWFudGlsZSgoYWxsU2ltSW5wdXRPdXRwdXQlPiUgZmlsdGVyKHBhcmFDb21ibyE9Im1STkFjb25zdGFudCIsIG1STkFEZWNSYXRlTmV5bW90aW5fc2VjIT0wLCBPUkYhPSJZRVIwNTNDLUEiKSkkTU1EUCkKCnRtcCA8LSAoYWxsU2ltSW5wdXRPdXRwdXQlPiVmaWx0ZXIocGFyYUNvbWJvPT0iZGNfMV9yXzAiKSlbLCBjKCJPUkYiLCAiUk1WVEUiKV0KdG1wIDwtIHRtcFtvcmRlcih0bXBbLCAyXSwgZGVjcmVhc2luZyA9IFQpLCBdCnRtcCRuZXdpZF9kYzFyMCA8LSAxOjQ4MzkKCmFsbFNpbUlucHV0T3V0cHV0ICU+JSAKICAgIG11dGF0ZShkY19mY3Q9ZmFjdG9yKGRjLCBsZXZlbHM9YygiMSIsICIwLjgiLCAiMC42IiwgIjAuNCIsICIwLjIiLCAiMCIpKSkgJT4lCiAgICBmaWx0ZXIocGFyYUNvbWJvIT0ibVJOQWNvbnN0YW50IiwgbVJOQURlY1JhdGVOZXltb3Rpbl9zZWMhPTAsIE9SRiE9IllFUjA1M0MtQSIsIGRjIT0wKSAlPiUgCiAgICBsZWZ0X2pvaW4oLiwgdG1wWywgYygiT1JGIiwgIm5ld2lkX2RjMXIwIildLCBieSA9ICJPUkYiKSAlPiUKICAgIGdncGxvdChhZXMoeCA9IHIsIAogICAgICAgICAgICAgICB5ID0gZmFjdG9yKG5ld2lkX2RjMXIwKSwKICAgICAgICAgICAgICAgZmlsbCA9IE1NRFApKSArCiAgICBnZW9tX3Jhc3RlcigpICsKICAgIHRoZW1lX2J3KCkgKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3VycyA9IGMoIiMzNzdlYjgiLCAid2hpdGUiLCAiI2U0MWExYyIpLCAgICMgYmx1ZSB3aGl0ZSByZWQKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBzY2FsZXM6OnJlc2NhbGUoY29sb3J2ZWMpLCBuYW1lPSJtUk5BcyBtYXJrZWRcbmZvciBkZWNheSByYXRpbyIpICsKICAgIGZhY2V0X3dyYXAofmRjX2ZjdCwgbnJvdz0xLCBsYWJlbGxlcj1sYWJlbGxlcihkY19mY3Q9YygiMSI9IkNvLXRyYW5zIDEwMCUiLCAiMC44Ij0iODAlIiwgIjAuNiI9IjYwJSIsICIwLjQiPSI0MCUiLCAiMC4yIj0iMjAlIiwgIjAiPSIwJSIpKSkgKwogICAgbGFicyAoIHggPSAiUmlib3NvbWUgcHJvdGVjdGlvbiBpbmRleCB3IiwKICAgICAgICAgICB5ID0gIkdlbmVzIHJhbmtlZCBieSB0aGUgZmlyc3QgY29sdW1uIGluIHRyYW5zbGF0aW9uIGVmZmljaWVuY3kgcGxvdCIsCiAgICAgICAgICAgdGl0bGUgPSAiIikgKwogICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpLAogICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPXJlbCgxLjUpKSwKICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLCAgIyByZW1vdmUgdGhlIGdyaWQgbGluZXMgaW4gZmFjZXRfZ3JpZAogICAgICAgICAgcGFuZWwuc3BhY2luZz11bml0KDAsICJsaW5lcyIpKSArICAgIyByZXNldCB0aGUgc3BhY2luZyBiZXR3ZWVuIGZhY2V0cwogICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMSwgYmFyaGVpZ2h0ID0gMTApKSArCiAgICAgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQgPSBjKDAsIDApKSAjIHJlbW92ZSB0aGUgZXh0cmEgc3BhY2UgYmV5b25kIHhsaW0KCmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9OH0KIyAxc3QgdmFyPSB0aGUgdmFyaWFibGUgY29sdW1uIHRoZSBzb3J0aW5nIGlzIGJhc2VkIG9uCiMgMm5kIHZhcj0gdGhlIHZhcmlhYmxlIGNvbHVtbiBwcmVzZW50ZWQgaW4gdGhlIGhlYXRtYXAKIyAzcmQgdmFyPSB0aGUgbGVnZW5kIHRleHQKIyA0dGggdmFyPSB5LWF4aXMgdGl0bGUKCm1ha2VfaGVhdG1hcCgiUk1QU1IiLCAiUk1QU1IiLCAiUmVsYXRpdmVcbm1lYW4gcHJvdGVpblxuc3luIHJhdGUiLCAiR2VuZXMgcmFua2VkIGJ5IHRoZSBmaXJzdCBjb2x1bW4iKQptYWtlX2hlYXRtYXAoIlJNVlBTIiwgIlJNVlBTIiwgIlJlbGF0aXZlXG5tZWFuIG9mIHZhcmlhbmNlIGluXG5wcm90ZWluIHN5biByYXRlIiwgIkdlbmVzIHJhbmtlZCBieSB0aGUgZmlyc3QgY29sdW1uIikKCm1ha2VfaGVhdG1hcF90bXAgPC0gZnVuY3Rpb24ob3JkZXJWYXIsIG91dHB1dFZhciwgbGVnZW5kTmFtZSwgdGl0bGVZKQp7CiAgICBjb2xvcnZlYyA8LSBxdWFudGlsZShhbGxTaW1JbnB1dE91dHB1dFtbb3V0cHV0VmFyXV0pCiAgCiAgICB0bXAgPC0gKGFsbFNpbUlucHV0T3V0cHV0JT4lZmlsdGVyKHBhcmFDb21ibz09ImRjXzFfcl8wIikpWywgYygiT1JGIiwgb3JkZXJWYXIpXQogICAgdG1wIDwtIHRtcFtvcmRlcih0bXBbLCAyXSwgZGVjcmVhc2luZyA9IFQpLCBdCiAgICB0bXAkbmV3aWRfZGMxcjAgPC0gMTo0ODM5CiAgICAKICAgIGFsbFNpbUlucHV0T3V0cHV0ICU+JSAKICAgICAgICBmaWx0ZXIocGFyYUNvbWJvIT0ibVJOQWNvbnN0YW50IiwgUk1WVEJSIT1JbmYpICU+JSAKICAgICAgICBsZWZ0X2pvaW4oLix0bXBbLCBjKCJPUkYiLCAibmV3aWRfZGMxcjAiKV0sIGJ5ID0gIk9SRiIpICU+JQogICAgICAgIG11dGF0ZShkY19mY3Q9ZmFjdG9yKGRjLCBsZXZlbHM9YygiMSIsICIwLjgiLCAiMC42IiwgIjAuNCIsICIwLjIiLCAiMCIpKSkgJT4lCiAgICAgICAgZ2dwbG90KGFlc19zdHJpbmcoeCA9ICJyIiwgCiAgICAgICAgICAgICAgICAgICB5ID0gImZhY3RvcihuZXdpZF9kYzFyMCkiLAogICAgICAgICAgICAgICAgICAgZmlsbCA9IG91dHB1dFZhcikpICsKICAgICAgICBnZW9tX3Jhc3RlcigpICsKICAgICAgICB0aGVtZV9idygpICsKICAgICAgICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvdXJzID0gYygiIzM3N2ViOCIsICJ3aGl0ZSIsICIjZTQxYTFjIiksICAgIyBibHVlIHdoaXRlIHJlZAogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBzY2FsZXM6OnJlc2NhbGUoY29sb3J2ZWMpLCBuYW1lPWxlZ2VuZE5hbWUpICsKICAgICAgICBmYWNldF93cmFwKH5kY19mY3QsIG5yb3c9MSwgbGFiZWxsZXI9bGFiZWxsZXIoZGNfZmN0PWMoIjEiPSJDby10cmFucyAxMDAlIiwgIjAuOCI9IjgwJSIsICIwLjYiPSI2MCUiLCAiMC40Ij0iNDAlIiwgIjAuMiI9IjIwJSIsICIwIj0iMCIpKSkgKyAKICAgICAgICBsYWJzICggeCA9ICJSaWJvc29tZSBwcm90ZWN0aW9uIGluZGV4IHIiLAogICAgICAgICAgICAgICB5ID0gdGl0bGVZLAogICAgICAgICAgICAgICB0aXRsZSA9ICIiKSArCiAgICAgICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpLAogICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksICAjIHJlbW92ZSB0aGUgZ3JpZCBsaW5lcyBpbiBmYWNldF9ncmlkCiAgICAgICAgICAgICAgcGFuZWwuc3BhY2luZz11bml0KDAsICJsaW5lcyIpKSArICAgIyByZXNldCB0aGUgc3BhY2luZyBiZXR3ZWVuIGZhY2V0cwogICAgICAgICBndWlkZXMoZmlsbCA9IGd1aWRlX2NvbG91cmJhcihiYXJ3aWR0aCA9IDEsIGJhcmhlaWdodCA9IDEwKSkgKwogICAgICAgICBzY2FsZV94X2Rpc2NyZXRlKGV4cGFuZCA9IGMoMCwgMCkpICMgcmVtb3ZlIHRoZSBleHRyYSBzcGFjZSBiZXlvbmQgeGxpbQoKfQptYWtlX2hlYXRtYXBfdG1wKCJSTVRFIiwgIlJNVlRCUiIsICJSZWxhdGl2ZVxudmFyaWFuY2UgaW4gdG90YWxcbmJvdW5kIHJpYm9zb21lcyIsICJHZW5lcyByYW5rZWQgYnkgdGhlIGZpcnN0IGNvbHVtbiBpbiByZWxhdGl2ZSBURSIpCgoKbWFrZV9oZWF0bWFwKCJNTUwiLCAiTU1MIiwgIk1lYW4gb2YgbVJOQVxubGlmZS10aW1lcyIsICJHZW5lcyByYW5rZWQgYnkgdGhlIGZpcnN0IGNvbHVtbiIpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKY29sb3J2ZWMgPC0gcXVhbnRpbGUoKGFsbFNpbUlucHV0T3V0cHV0JT4lIGZpbHRlcihwYXJhQ29tYm8hPSJtUk5BY29uc3RhbnQiLCBtUk5BRGVjUmF0ZU5leW1vdGluX3NlYyE9MCwgT1JGIT0iWUVSMDUzQy1BIikpJFJNUkQpCgp0bXAgPC0gKGFsbFNpbUlucHV0T3V0cHV0JT4lZmlsdGVyKHBhcmFDb21ibz09ImRjXzFfcl8wIikpWywgYygiT1JGIiwgIlJNVEUiKV0KdG1wIDwtIHRtcFtvcmRlcih0bXBbLCAyXSwgZGVjcmVhc2luZyA9IFQpLCBdCnRtcCRuZXdpZF9kYzFyMCA8LSAxOjQ4MzkKCgphbGxTaW1JbnB1dE91dHB1dCAlPiUgCiAgICBmaWx0ZXIocGFyYUNvbWJvIT0ibVJOQWNvbnN0YW50IiwgbVJOQURlY1JhdGVOZXltb3Rpbl9zZWMhPTAsIE9SRiE9IllFUjA1M0MtQSIpICU+JSAKICAgIGxlZnRfam9pbiguLCB0bXBbLCBjKCJPUkYiLCAibmV3aWRfZGMxcjAiKV0sIGJ5ID0gIk9SRiIpICU+JQogICAgZ2dwbG90KGFlcyh4ID0gciwgCiAgICAgICAgICAgICAgIHkgPSBmYWN0b3IobmV3aWRfZGMxcjApLAogICAgICAgICAgICAgICBmaWxsID0gUk1SRCkpICsKICAgIGdlb21fcmFzdGVyKCkgKwogICAgdGhlbWVfYncoKSArCiAgICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvdXJzID0gYygiIzM3N2ViOCIsICJ3aGl0ZSIsICIjZTQxYTFjIiksICAgIyBibHVlIHdoaXRlIHJlZAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IHNjYWxlczo6cmVzY2FsZShjb2xvcnZlYyksIG5hbWU9IlJlbGF0aXZlIG1lYW5cbnJpYm8gZGVuc2l0eSIpICsKICAgIGZhY2V0X3dyYXAofmRjLCBucm93PTEsIGxhYmVsbGVyPWxhYmVsbGVyKGRjPWMoIjEiPSJDby10cmFucyAxMDAlIiwgIjAuOCI9IjAuOCIsICIwLjYiPSIwLjYiLCAiMC40Ij0iMC40IiwgIjAuMiI9IjAuMiIsICIwIj0iMCIpKSkgKwogICAgbGFicyAoIHggPSAiUmlib3NvbWUgcHJvdGVjdGlvbiBpbmRleCIsCiAgICAgICAgICAgeSA9ICJHZW5lcyByYW5rZWQgYnkgdGhlIGZpcnN0IGNvbHVtbiBmb3IgdHJhbnNsYXRpb24gZWZmaWNpZW5jeSIsCiAgICAgICAgICAgdGl0bGUgPSAiIikgKwogICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpLAogICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPXJlbCgxLjUpKSwKICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLCAgIyByZW1vdmUgdGhlIGdyaWQgbGluZXMgaW4gZmFjZXRfZ3JpZAogICAgICAgICAgcGFuZWwuc3BhY2luZz11bml0KDAsICJsaW5lcyIpKSArICAgIyByZXNldCB0aGUgc3BhY2luZyBiZXR3ZWVuIGZhY2V0cwogICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfY29sb3VyYmFyKGJhcndpZHRoID0gMSwgYmFyaGVpZ2h0ID0gMTApKSArCiAgICAgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQgPSBjKDAsIDApKSAjIHJlbW92ZSB0aGUgZXh0cmEgc3BhY2UgYmV5b25kIHhsaW0KYGBgCg==